为什么我不能直接在C#中比较表达式和null?

时间:2013-09-21 16:01:41

标签: c#

        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 个答案:

答案 0 :(得分:3)

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

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

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()而不使用参数来查看所有可用的模式选项。

答案 1 :(得分:1)

IDbCommand.ExecuteScalar是底层接口方法。根据此方法的documentation

“如果未找到结果集中第一行的第一列,则返回空引用(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
}

答案 2 :(得分:0)

你没有得到返回空值的那么多。在此之前,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);
}

答案 3 :(得分:0)

这里有两个问题: -

  1. 如何在ExecuteScalar上处理异常如果表不存在。
  2. 如何关闭连接/命令(不使用GoTo 语句)
  3. 对于1),我不太同意先检查架构。你应该把这个Db操作真的放在一个函数中然后用try / catch包装函数并以标准方式处理(错误报告/日志等)

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