0
        cmd = new SQLiteCommand();
        ...
        if (Convert.ToInt32(cmd.ExecuteScalar()) == 0)
            goto doClose;
        else
            cmd.CommandText = sql;
        reader = cmd.ExecuteReader(); // this is line 182, check the exception details below

更多:我要睡觉了。下面是代码源(我来自 GitHub 的仓库),如果有人可以看一下吗?git@github.com:tomxuetoy/WPF_startPrograms.git

以上是我的代码,它可以正常工作。在我的情况下cmd.ExecuteScalar(),由于SQLite表不存在,将返回 null。我试图改变它,如下所示,但失败了:

if (cmd.ExecuteScalar() == null)

所以我想知道为什么我不能直接压缩表达式(null返回)null?谢谢!

更多:尝试了以下但结果相同:无法工作

if (cmd.ExecuteScalar() == DBNull.Value)
or
if (cmd.ExecuteScalar() is DBNull)

详细的异常复制如下,但有一些汉字......

System.Windows.Markup.XamlParseException occurred
  HResult=-2146233087
  Message=对类型“MultiStart.MainWindow”的构造函数执行符合指定的绑定约束的调用时引发了异常。
  Source=PresentationFramework
  LineNumber=0
  LinePosition=0
  StackTrace:
       在 System.Windows.Markup.WpfXamlLoader.Load(XamlReader xamlReader, IXamlObjectWriterFactory writerFactory, Boolean skipJournaledProperties, Object rootObject, XamlObjectWriterSettings settings, Uri baseUri)
  InnerException: System.Data.SQLite.SQLiteException
       HResult=-2147467259
       Message=SQLite error
no such table: testTable
       Source=System.Data.SQLite
       ErrorCode=-2147467259
       StackTrace:
            在 System.Data.SQLite.SQLite3.Prepare(SQLiteConnection cnn, String strSql, SQLiteStatement previous, UInt32 timeoutMS, String& strRemain)
            在 System.Data.SQLite.SQLiteCommand.BuildNextCommand()
            在 System.Data.SQLite.SQLiteCommand.GetStatement(Int32 index)
            在 System.Data.SQLite.SQLiteDataReader.NextResult()
            在 System.Data.SQLite.SQLiteDataReader..ctor(SQLiteCommand cmd, CommandBehavior behave)
            在 System.Data.SQLite.SQLiteCommand.ExecuteReader(CommandBehavior behavior)
            在 System.Data.SQLite.SQLiteCommand.ExecuteReader()
            在 MultiStart.MainWindow.dbOp(dowhat dw) 位置 c:\Users\Administrator\Desktop\WPF_startPrograms\WpfApplication2\WpfApplication2\MainWindow.xaml.cs:行号 182
            在 MultiStart.MainWindow.DataBinding() 位置 c:\Users\Administrator\Desktop\WPF_startPrograms\WpfApplication2\WpfApplication2\MainWindow.xaml.cs:行号 43
            在 MultiStart.MainWindow..ctor() 位置 c:\Users\Administrator\Desktop\WPF_startPrograms\WpfApplication2\WpfApplication2\MainWindow.xaml.cs:行号 36
       InnerException: 
4

4 回答 4

3

更好的方法是先检查表是否存在。其中一种方法是调用DbConnection.GetSchema(string)传入 SqlLite 用于其表模式的任何参数。

我没有要测试的 SqlLite 数据库,但它会是这样的

var tableName = "testTable";
var commandText = "Select * from " + tableName;

using(var conn = new SQLiteConnection(connectionString))
{
    conn.Open();

    var schema = conn.GetSchema("Tables", new string[] { null, null, tableName });
    if(schema.Rows.Count == 0) //I am assuming your original ExecuteScalar query was some kind of "If Exists" query to test for the table.
        return;

    using(var cmd = new SQLiteCommand(commandText, conn))
    {
        using(var reader = cmd.ExecuteReader())
        {
              //....
        }
    }
}

如果列出所有可用表的模式名称不Tables只是conn.GetSchema()不带参数调用以查看模式的所有可用选择。

于 2013-09-21T16:32:12.160 回答
1

您不会得到返回空值的那么远。在它执行之前Reader(和/或ExecuteScalar) 会向您抛出异常。抓住它并相应地处理......

try 
{
       if (Convert.ToInt32(cmd.ExecuteScalar()) == 0)
            goto doClose; // Really? That must be complex then...
        else
            cmd.CommandText = sql;
        reader = cmd.ExecuteReader(); 
}
catch(SQLiteException exp)
{
       Trace.WriteLine( exp.Message);
}
于 2013-09-21T16:17:41.027 回答
1

IDbCommand.ExecuteScalar 是底层接口方法。根据此方法的文档:

“如果未找到结果集中第一行的第一列,则返回空引用( Visual Basic 中为Nothing)。如果数据库中的值为null,则查询返回DBNull.Value ”。

您的代码应该处理任何一种情况。

但是......如果您的查询中指定的表不存在,您将抛出异常,就像您遇到任何其他失败情况(查询中的语法错误等)一样。您应该使用 try/catch 逻辑包装所有数据库交互;几乎所有您可能对数据库执行的任何操作都存在失败案例,并且所有失败案例都通过抛出异常传达给您的应用程序代码。

try
{
    var result = cmd.ExecuteScalar();
    if (result == null)
    {
        // handle null case
    }
    else if (result is DbNull)
    {
        // handle DbNull case
    }
    else
    {
        // usable result you can cast as appropriate
    }
}
catch (Exception ex)
{
    // Handle all other eventualities
}
于 2013-09-21T16:37:21.180 回答
0

这里有两个问题:-

  1. 如果表不存在,如何处理 ExecuteScalar 上的异常。
  2. 如何可能关闭连接/命令(不使用 GoTo 语句)

对于 1),我不太同意先检查架构。您真的应该将此 Db 操作放在一个函数中,然后将函数包装在 try/catch 中并以标准方式处理(错误报告/日志等)

对于 2) 如果您期望,您的查询返回 1 行或多行,为什么要使用 ExecuteScalar 呢?为什么不只使用 ExecuteReader() 来检索一行或多行。此外,将阅读器包装在“使用”块中,以确保关闭连接/阅读器。

于 2013-09-21T16:45:11.803 回答