如何从数据库中获取可空的DateTime?

20

我的 SQL Server 数据库包含可空的 DateTime 值。我该如何在 C# 应用程序中将它们转换为可空的 DateTime 对象?

以下是我认为会有效果的代码,但实际上不行:

DateTime? dt = (DateTime?) sqldatareader[0];

1
它为什么不工作?你是否收到异常? - jrummell
1
请不要在标题前加标签。已经有标签的存在了。 - cadrell0
7个回答

35

SQL中的null和.NET中的null不同,您需要与System.DBNull.Value进行比较:

object sqlDateTime = sqldatareader[0];
DateTime? dt = (sqlDateTime == System.DBNull.Value)
    ? (DateTime?)null
    : Convert.ToDateTime(sqlDateTime);
回答你的评论,DataReaderItem 属性数据类型是底层数据库类型的数据类型。它可以是非空 SQL Server 数据库的 System.Data.SqlTypes.SqlDateTime,或者是空列的 System.DBNull,或者是 ODBC 数据库的 System.Data.Odbc.OdbcTypes.SmallDateTime,实际上可以是任何类型。你唯一能依赖的是它是 object 类型。
这也是为什么我建议使用 Convert.ToDateTime() 而不是类型强制转换成 DateTime。不能保证 ODBC 或其他日期列可以强制转换为 .NET DateTime。我注意到你的评论指定了一个 "sqldatareader",而 SQL Server 的 System.Data.SqlTypes.SqlDateTime 确实可以强制转换为 System.DateTime,但是你原来的问题没有告诉我们这一点。
有关使用 DataReader 的更多信息,请参阅MSDN

33

我最近发现了这个技巧,很简单:

var dt = sqldatareader[0] as DateTime?;

非常精确的解决方案!我从现在开始将使用这个方法,而不是更繁琐的三元方法。 - Baxter
你能解释一下吗?我不明白为什么DateTime后面会有一个问号。 - MDB
1
@MDB 只是表示它是可空的 DateTime。 - JoJo

3
创建助手方法如何?
private static DateTime? MyDateConverter(object o)
{
    return (o == DBNull.Value || o == null) ? (DateTime?)null : Convert.ToDateTime(o);
}

使用方法

MyDateConverter(sqldatareader[0])

2

1
不久前,我为DataRow编写了一堆扩展方法,以执行此类向下转换...因为我讨厌编写重复的废话。使用方法很简单:
foreach( DataRow dr in someDataTable )
{
  DateTime? dt = dr.CastAsDateTimeNullable( "lastUpdated" ) ;
  int       id = dr.CastAsInt( "transactionID" ) ;
  // etc.
}

这里是关于 DateTime 值的代码片段。为其他数据类型添加实现应该相当容易。如果有兴趣,也可以对 DataReader 进行类似的操作。

我尝试想出通用方法,但泛型的限制使得这很难或不可能实现,并且仍然能够获得我想要的行为(例如,null 值而不是 default(T) - 获取 SQL NULL 的默认值,这将使得区分 0null ... 很困难)。

public static class DataRowExtensions
{

  #region downcast to DateTime

  public static DateTime CastAsDateTime( this DataRow row , int index )
  {
    return toDateTime( row[index] ) ;
  }
  public static DateTime CastAsDateTime( this DataRow row , string columnName )
  {
    return toDateTime( row[columnName] ) ;
  }

  public static DateTime? CastAsDateTimeNullable( this DataRow row , int index )
  {
    return toDateTimeNullable( row[index] );
  }
  public static DateTime? CastAsDateTimeNullable( this DataRow row , string columnName )
  {
    return toDateTimeNullable( row[columnName] ) ;
  }

  #region conversion helpers

  private static DateTime toDateTime( object o )
  {
    DateTime value = (DateTime)o;
    return value;
  }

  private static DateTime? toDateTimeNullable( object o )
  {
    bool  hasValue = !( o is DBNull );
    DateTime? value    = ( hasValue ? (DateTime?) o : (DateTime?) null ) ;
    return value;
  }

  #endregion

  #endregion downcast to DateTime

  // ... other implementations elided .. for brevity

}

0
DateTime? dt = null;

if (sqldatareader[0] != System.DbNull.Value)
{
    dt = (DateTime)sqldatareader[0];
}

-1

只需使用:

System.Nullable<System.DateTime> yourVariableName;

让它变得简单 :)


这与数据库有什么关系? - deW1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接