使用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
分配给从数据库读取的值的位置,因为它未显示在已发布的代码中。 这就是我在我的示例中直接分配它的原因,但您可能需要调整示例逻辑的位置。