使用SQLDataReader可以为Nulllable DateTime

我几乎不想问这个问题似乎已被问过一百万次,但即使我研究了另一个问题,我仍然无法在我的案例中弄明白这一点。

我读到DateTime是一个可以为空的类型,我尝试了一些例子,但我试图弄清楚数据库中我的SQLDATAREADER是否失败是否为NULL。

错误

System.Data.SqlTypes.SqlNullValueException:数据为空。 无法在Null值上调用此方法或属性。

DetailsClass

private DateTime? startingDate; public DateTime? StartingDate { get{ return startingDate; } set{ startingDate = value; } } // constructor Public DetailsClass(DateTime? startingDate) { this.startingDate = startingDate; } 

DBClass

  using (SqlConnection con = new SqlConnection(connectionString)) using (SqlCommand cmd = con.CreateCommand()) { List details = new List(); DetailsClass dtl; try { con.Open(); cmd.CommandText = "Stored Procedure Name"; cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.AddWithValue("@MyParameter", myparameter); using (SqlDataReader reader = cmd.ExecuteReader()) { while (reader.Read()) { dtl = new DetailsClass(( reader.GetInt32(reader.GetOrdinal("MEMBERSHIPGEN"))), reader.IsDBNull(1) ? null : reader.GetString(reader.GetOrdinal("EMAIL")), reader.GetDateTime(reader.GetOrdinal("STARTINGDATE"))); details.Add(dtl); } reader.Close(); return details; } } 

这是一个从读者那里获取价值的辅助方法

 public static class ReaderExtensions { public static DateTime? GetNullableDateTime(this SqlDataReader reader, string name){ var col = reader.GetOrdinal(name); return reader.IsDBNull(col) ? (DateTime?)null : (DateTime?)reader.GetDateTime(col); } } 

有关如何使用以响应评论的更新

 using (SqlConnection con = new SqlConnection(connectionString)) using (SqlCommand cmd = con.CreateCommand()) { List details = new List(); DetailsClass dtl; try { con.Open(); cmd.CommandText = "Stored Procedure Name"; cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.AddWithValue("@MyParameter", myparameter); using (SqlDataReader reader = cmd.ExecuteReader()) { while (reader.Read()) { dtl = new DetailsClass(( reader.GetInt32(reader.GetOrdinal("MEMBERSHIPGEN"))), reader.IsDBNull(1) ? null : reader.GetString(reader.GetOrdinal("EMAIL")), reader.GetNullableDateTime("STARTINGDATE")); details.Add(dtl); } reader.Close(); return details; } } 

另请注意,您使用的是reader.IsDBNull(1) ,然后是reader.GetOrdinal 。 可能应该是reader.IsDBNull(reader.GetOrdinal("EMAIL"))

更换

 DateTime startingDate; 

 DateTime? startingDate; 

问号将其标记为可以为空的值,并且您的读者应该能够将startingdate设置为null而不是抛出exception。

您还可以在阅读器工作时检查空值,并用空字符串替换空值

 while(reader.read()) { //column is an int value of your column. Ie: if the column ist the 8th column, set column to 7 (0-based) StartingDate = (reader.IsDBNull(column)) ? null : reader.GetOrdinal("STARTINGDATE")); //instead of null you could also return a specific date like 1.1.1900 or String.Empty } 

你能告诉我们在调试时究竟是哪一行引发了错误。 这会更容易。

 if (! reader.IsDBNull(reader.GetOrdinal("STARTINGDATE"))) { obj.startingDate = reader.GetDateTime(reader.GetOrdinal("STARTINGDATE")); } 

如果它是DBNull,则无需显式指定null,因为它是可空类型,因此默认情况下它将包含null。

好的,根据您更新的代码(注意评论):

 while (reader.Read()) { dtl = new DetailsClass((reader.GetInt32(reader.GetOrdinal("MEMBERSHIPGEN"))), // here you are checking null for email reader.IsDBNull(1) ? null : reader.GetString(reader.GetOrdinal("EMAIL")), // here you are not checking null for startingdate ? reader.GetDateTime(reader.GetOrdinal("STARTINGDATE"))); details.Add(dtl); } 

让我们以更详细的方式尝试:

 while (reader.Read()) { dtl = new DetailsClass(); dtl.membershipgen = reader.IsDBNull(reader.GetOrdinal("MEMBERSHIPGEN")) ? null : reader.GetInt32(reader.GetOrdinal("MEMBERSHIPGEN")); dtl.email = reader.IsDBNull(reader.GetOrdinal("EMAIL")) ? null : reader.GetString(reader.GetOrdinal("EMAIL")), dtl.startingdate = reader.IsDBNull(reader.GetOrdinal("STARTINGDATE")) ? null : reader.GetDateTime(reader.GetOrdinal("STARTINGDATE"))); details.Add(dtl); } 

我知道这个问题已得到解答,但进一步简化了代码以处理其他可以为null的变量类型。 上面的答案仅限于一种特定的变量类型。 关于这一点的好处是它还允许您包含默认值而不是将其设置为null。

 public static T GetDataType( this SqlDataReader r, string name, object def = null ) { var col = r.GetOrdinal(name); return r.IsDBNull(col) ? (T)def : (T)r[name]; } 

然后在代码中,你可以使用如

 ... while(reader.Read()) { data1Bool = reader.GetDataType("data1"); // if it's null then we'll set it as null data2intNotNull = reader.GetDataType("data2", 0); // if the data is null, then we'll set to 0 data3date = reader.GetDataType("data3", DateTime.Now); // same example as above, but instead of setting to 0, I can default it to today's date. } ... 

我还有关于无效值对象的其他问题,这节省了我数小时试图找出正在发生的事情。 (WPF在编译运行时没有解释该问题。)

试试这个:

使startingDate变量可以为nullable ,如下所示:

 DateTime? startingDate; 

现在,当从SqlDataReader对象中检索值时,您需要使用IsDbNull方法,该方法将确定从数据库返回的值是否为NULL ,如下所示:

 if !reader.IsDBNull(reader.GetOrdinal("STARTINGDATE")) { startingDate = reader.GetDateTime(reader.GetOrdinal("STARTINGDATE")); } else { startingDate = null; } 

注意:我不确定将startingDate分配给从数据库读取的值的位置,因为它未显示在已发布的代码中。 这就是我在我的示例中直接分配它的原因,但您可能需要调整示例逻辑的位置。