7

说我有这门课:

class myclass
{
    public int Field1{ get; set; }
    public int? Field2 { get; set; } //Note Field2 is nullable
 }

我正在尝试使用来自数据库的数据填充通用列表。由于 GetSqlInt32 实现了 INullable 我会认为下面的代码会起作用。它没有。如果 Field2 为空,则会生成错误。

List<myclass> mylist=new List<myclass>();

int Field1_Ordinal = rdr.GetOrdinal("Field1");
int Field2_Ordinal = rdr.GetOrdinal("Field2");

SqlDataReader rdr = cmd.ExecuteReader(); //Execute a stored procedure to retrieve data from the database

while (rdr.Read())
 {
   mylist.Add(new myclass
   {
      Field1 = rdr.GetSqlInt32(Field1_Ordinal).Value,
      Field2 = rdr.GetSqlInt32(Field2_Ordinal).Value  //Error if field2 is null
   });
 }

任何想法为什么它不起作用?

4

7 回答 7

24

在我看来,您需要这样的转换(为方便起见,使用扩展方法):

public static int? ToNullableInt32(this SqlInt32 value)
{
    return value.IsNull ? (int?) null : value.Value;
}

然后:

Field2 = rdr.GetSqlInt32(Field2_Ordinal).ToNullableInt32()

(评论其他答案:没有必要DbNull引入这个,因为SqlInt32已经可以表示空值。你只需要在使用之前检测到它Value。)

于 2009-09-01T13:51:04.567 回答
6

看看这个不是我写的解决方案:

employee.FirstName = sqlreader[indexFirstName] as string;
employee.Age = sqlreader[indexAge] as int? ?? default(int);

它最初是在这里提出的:

SQL 数据阅读器 - 处理 Null 列值

于 2011-08-26T17:58:59.977 回答
4

这是该主题的减轻疼痛的变体。如果有人知道如何将 Val 和 Ref 合并到一个模板函数中,请随意发布。您将必须明确说明类型(C# 编译不能被打扰 :-) 但这:

var dd = r.Val<DateTime>(ords[4]);
var ii = r.Def<int>(ords[0]);
int nn = r.Def<int>(ords[0]);

仍然让我的手指开心:-)

public static T Def<T>(this SqlDataReader r, int ord)
{
    var t = r.GetSqlValue(ord);
    if (t == DBNull.Value) return default(T);
    return ((INullable)t).IsNull ? default(T) : (T)t;
}

public static T? Val<T>(this SqlDataReader r, int ord) where T:struct
{
    var t = r.GetSqlValue(ord);
    if (t == DBNull.Value) return null;
    return ((INullable)t).IsNull ? (T?)null : (T)t;
}

public static T Ref<T>(this SqlDataReader r, int ord) where T : class
{
    var t = r.GetSqlValue(ord);
    if (t == DBNull.Value) return null;
    return ((INullable)t).IsNull ? null : (T)t;
}
于 2010-07-22T10:35:18.307 回答
1

认为这是因为返回的值是DBNull.Value,而不是null

相反,您可以使用 IsDbNull() 方法在读取字段之前检查该字段是否为空。

于 2009-09-01T13:49:39.000 回答
1

您必须在阅读器上使用特殊方法来检测值何时为空

mylist.Add(new myclass   
{      
     Field1 = rdr.IsDbNull(Field1_Ordinal)? 0: 
               rdr.GetSqlInt32(Field1_Ordinal).Value,      
     Field2 = rdr.IsDbNull(Field2_Ordinal)? 0:  // whatever default value you wish...
               rdr.GetSqlInt32(Field2_Ordinal).Value  // No error now
});
于 2009-09-01T13:50:53.147 回答
1

我正在尝试导出一个包含 39 个字段的 Access 数据库 - 许多字段为 NULL 值。我无法让扩展方法工作,所以我编写了以下函数:

private string ChkDbStr(object inObj)
{
  if (inObj == null)
  { return ""; }
  else
  { return inObj.ToString(); }
}

当我读取每个可能包含 NULL 的字段时,我将字段编码为:ChkDbStr(DbReader.GetValue(1))

于 2010-12-06T20:39:16.263 回答
0

DbNull.Value != null

所以你需要一个?: 表达式或 if 块将数据库空值转换为 c# 空值,反之亦然。

于 2009-09-01T13:48:37.673 回答