24

我几乎不想问这个问题,好像它已经被问过一百万次了,但即使我研究了另一个问题,我似乎仍然无法在我的情况下解决这个问题。

我读到 DateTime 是一个可为空的类型,我尝试了一些示例,但我试图确定它在我的 SQLDATAREADER 失败的数据库中是否为 NULL。

错误

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

详情类

private DateTime? startingDate;

public DateTime? StartingDate
{
    get{ return startingDate; }
    set{ startingDate = value; }
}

// constructor
Public DetailsClass(DateTime? startingDate)
{
    this.startingDate = startingDate;
}

数据库类

   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;

                    }
                }
4

5 回答 5

53

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

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)then reader.GetOrdinal。大概应该是reader.IsDBNull(reader.GetOrdinal("EMAIL"))

于 2013-07-05T14:10:22.423 回答
4

代替

DateTime startingDate;

DateTime? startingDate;

问号将其标记为可空值,您的读者应该能够将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
}
于 2013-07-05T13:25:11.753 回答
2

我知道这个问题已经得到解答,但进一步简化了处理其他可为空变量类型的代码。上面的答案只限于一种特定的变量类型。这样做的好处是它还允许您包含默认值而不是将其设置为 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.
}
...

我还有其他关于可空值对象的问题,这节省了我数小时试图弄清楚发生了什么的时间。(WPF 在编译运行时没有解释这个问题。)

于 2018-08-28T23:30:40.783 回答
1

您能否准确告诉我们调试时哪一行引发了错误。这会更容易。

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);
}
于 2013-07-05T14:17:58.673 回答
0

试试这个:

制作startingDate变量nullable,如下所示:

DateTime? startingDate;

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

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

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

于 2013-07-05T13:50:33.080 回答