【问题标题】:What is the best practice for handling null int/char from a SQL Database?处理 SQL 数据库中的 null int/char 的最佳做法是什么?
【发布时间】:2008-11-25 19:24:12
【问题描述】:

我有一个保存用户可选配置文件的数据库。在配置文件中,我有字符串、char(用于 M 或 F)和 ints。

我遇到了一个问题,我尝试将用户的性别放入我的 Profile 对象的属性中,但应用程序崩溃了,因为它不知道如何处理返回的空值。

我已经尝试将数据转换为适当的类型

char sex = (char)dt.Rows[0]["Sex"];

这并没有解决我的问题。然后我尝试将类型更改为 Nullable 和 Nullable 并得到相同的转换问题。我目前能够找到的解决方案如下:

object.sex = null;  
if(dt.Rows[0]["Sex"] != DBNull.Value)
      object.sex = (char)dt.Rows[0]["Sex"];
object.WorkExt = null;
if(dt.Rows[0]["WorkExt"] != DBNull.Value)
      object.WorkExt = (int)dt.Rows[0]["WorkExt"];

有没有更简单或更好的方法来做到这一点?还是我几乎走在正确的轨道上?

【问题讨论】:

    标签: c# sql-server dbnull


    【解决方案1】:

    rotard 的回答(使用Is<ColumnName>Null())仅适用于类型化数据集。

    对于无类型数据集,您必须使用以下代码中的模式之一。如果此代码不是确定的,请告诉我,我将对其进行编辑,直到确定为止。这是一个极其常见的问题,实际上应该只有一个正确答案。

    using System.
    using System.Data;
    
    class Program
    {
        static void Main(string[] args)
        {
            DataTable dt = new DataTable();
            dt.Columns.Add("test", typeof (char));
            dt.Columns["test"].AllowDBNull = true;
    
            DataRow dr = dt.Rows.Add();
            char? test;
    
            try
            {
                test = (char?)dr["test"];
            }
            catch (InvalidCastException)
            {
                Console.WriteLine("Simply casting to a nullable type doesn't work.");
            }
    
            test  = dr.Field<char?>("test");
            if (test == null)
            {
                Console.WriteLine("The Field extension method in .NET 3.5 converts System.DBNull to null.");                
            }
    
            test = (dr["test"] is DBNull) ? null : (char?) dr["test"];
            if (test == null)
            {
                Console.WriteLine("Before .NET 3.5, you have to check the type of the column's value.");
            }
    
            test = (dr["test"] == DBNull.Value) ? null : (char?) dr["test"];
            if (test == null)
            {
                Console.WriteLine("Comparing the field's value to DBNull.Value is very marginally faster, but takes a bit more code.");
            }
    
            // now let's put the data back
    
            try
            {
                dr["test"] = test;
            }
            catch (ArgumentException)
            {
                Console.WriteLine("You can't set nullable columns to null.");
            }
    
            dr.SetField("test", test);
            if (dr["test"] is DBNull)
            {
                Console.WriteLine("Again, in .NET 3.5 extension methods make this relatively easy.");
            }
    
            dr["test"] = (object)test ?? DBNull.Value;
            if (dr["test"] is DBNull)
            {
                Console.WriteLine("Before .NET 3.5, you can use the null coalescing operator, but note the awful cast required.");
            }
    
    
            Console.ReadLine();
        }
    }
    

    【讨论】:

      【解决方案2】:

      可空类型就是为此目的而设计的!使用“作为字符?”而不是 '(char?)'

      class Foo {
          char? sex;
      }
      Foo object;
      
      object.sex = dt.Rows[0]["Sex"] as char?;
      

      【讨论】:

      • 遗憾的是,这不是可空类型的设计目的,如果您测试该代码就会发现。如果 DataColumn 设置了 AllowDBNull,则该列中的空值是 DBNull.Value,而不是空值。您的代码会引发 InvalidCastException。
      • 'as' 什么时候抛出 InvalidCastException 异常?
      【解决方案3】:

      【讨论】:

      • 这有点不同,因为它不会用 DBNull 覆盖现有值
      【解决方案4】:

      怎么样:

          internal static T CastTo<T>(object value)
          {
              return value != DBNull.Value ? (T)value : default(T);
          }
      

      然后像这样使用它:

              return new EquipmentDetails(
                  CastTo<int>(reader["ID"]),
                  CastTo<int>(reader["CategoryID"]),
                  CastTo<string>(reader["Description"]));
      

      等等……

      【讨论】:

        【解决方案5】:

        dt 是 ADO.Net 2 数据表吗?你能不能不这样做:

        if(dt.Rows[0].IsSexNull()) {} else {}
        

        ?另外,假设您可以控制您的数据库,使用 bit 而不是 string 是否更有意义?

        【讨论】:

        • 有些困惑的人真的不知道如何回答这个问题,有些人只是不想告诉你。您可以将这些组放在一起,但至少需要第三个选项。
        • 使用位的明显问题是,即使 Sex 是二元选择,True 和 False 的含义也不是不言而喻的。此外,在许多系统中,它甚至不是三元选择:我正在使用的一个支持男性、女性、未知和拒绝状态。还有NULL,和“Unknown”不一样。
        【解决方案6】:

        我会像你一样做。我会为它写一个函数:

        做的事情:

        object.sex = handle(dt.Rows[0]["Sex"]);
        

        在句柄中你做 ==DBNull.Value 检查。

        【讨论】:

        • 只有当你的函数返回一个对象并且你将返回值转换为char时才有效?在作业中。 .NET 3.5 的 DataRow 扩展中的 Field 方法为您完成了这项工作。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多