Nullable DateTime with SQLDataReader
本文关键字:SQLDataReader with DateTime Nullable | 更新日期: 2023-09-27 18:21:24
我几乎不想问这个问题,这个问题以前似乎已经被问了一百万次了,但即使我在研究另一个问题,我似乎仍然无法在我的情况下弄清楚这一点。
我读到DateTime是一个可以为NULL的类型,我尝试了一些例子,但我试图弄清楚它在我的SQLDATAREADER失败的数据库中是否为NULL。
错误
System.Data.SqlTypes.SqlNullValueException:数据为Null。不能"对Null值调用"此方法或属性
细节类别
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<DetailsClass> details = new List<DetailsClass>();
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<DetailsClass> details = new List<DetailsClass>();
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;
问号将其标记为可为null的值,读者应该能够将startingdate设置为null,而不是引发异常。
您也可以在阅读器工作时检查空值,并用空字符串替换空值
while(reader.read())
{
//column is an int value of your column. I.e: 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
}
我知道这个问题已经得到了回答,但进一步简化了代码以处理其他可为null的变量类型。上面的答案仅限于一种特定的变量类型。这样做的好处是,它还允许您包含一个默认值,而不是将其设置为null。
public static T GetDataType<T>( 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<bool?>("data1"); // if it's null then we'll set it as null
data2intNotNull = reader.GetDataType<int>("data2", 0); // if the data is null, then we'll set to 0
data3date = reader.GetDataType<DateTime?>("data3", DateTime.Now); // same example as above, but instead of setting to 0, I can default it to today's date.
}
...
我遇到了关于null值对象的其他问题,这让我节省了几个小时来弄清楚发生了什么。(WPF在编译运行时没有解释这个问题。)
你能告诉我们调试时到底是哪一行抛出了错误吗。这会更容易。
if (! reader.IsDBNull(reader.GetOrdinal("STARTINGDATE"))) {
obj.startingDate = reader.GetDateTime(reader.GetOrdinal("STARTINGDATE"));
}
如果它是DBNull,则无需显式分配null,因为它是一个可为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);
}
试试这个:
使startingDate
变量nullable
,如下所示:
DateTime? startingDate;
现在,当从SqlDataReader
对象检索值时,您需要使用IsDbNull
方法,该方法将确定该值是否为从数据库返回的NULL
,如下所示:
if !reader.IsDBNull(reader.GetOrdinal("STARTINGDATE"))
{
startingDate = reader.GetDateTime(reader.GetOrdinal("STARTINGDATE"));
}
else
{
startingDate = null;
}
注意:我不确定您将startingDate
分配给从数据库读取的值的位置,因为它没有显示在发布的代码中。这就是为什么我在示例中直接分配它,但您可能需要调整示例逻辑的位置。