Sql server 2008 SQL Server 2008日期列值存在Fluent NHibernate问题

Sql server 2008 SQL Server 2008日期列值存在Fluent NHibernate问题,sql-server-2008,exception,date,fluent-nhibernate,Sql Server 2008,Exception,Date,Fluent Nhibernate,您好 我在使用Fluent NHibernate使用C#中的SQL Server 2008DATE列时遇到问题 当我尝试更新一条记录时,如果该记录在1753年1月1日(DATETIME的最小日期)之前的不可为NULL的DATE列中有一个值,我会收到一个错误,说明它无法在该列中插入NULL。如果该值大于1/1/1753,则不存在问题,并保留正确的日期值 这是我的模型文件: public class Table1 : model.DBObject { public virtual Int32 T

您好

我在使用Fluent NHibernate使用C#中的SQL Server 2008
DATE
列时遇到问题

当我尝试更新一条记录时,如果该记录在1753年1月1日(DATETIME的最小日期)之前的不可为NULL的
DATE
列中有一个值,我会收到一个错误,说明它无法在该列中插入NULL。如果该值大于1/1/1753,则不存在问题,并保留正确的日期值

这是我的模型文件:

public class Table1 : model.DBObject
{
  public virtual Int32 TestID { get; private set; }
  public virtual String Description { get; set; }
  public virtual DateTime TestDate { get; set; }

  public Table1()
  {
  }

  public static Table1 Load(DBSess sess, Int32 TestID)
  {
      return (Table1)sess.Session.Get(typeof(Table1), TestID);
  }
}
我的映射文件:

public class Table1Map : ClassMap<Table1>
{
  public Table1Map()
  {
    Table("[Table1]");
    Id(x => x.TestID).GeneratedBy.Identity();
    Map(x => x.Description).Not.Nullable();
    Map(x => x.TestDate).Not.Nullable().CustomType("date");
  }
}
导出的NHibernate映射:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-access="property" auto-import="true" default-cascade="none" default-lazy="true">
  <class xmlns="urn:nhibernate-mapping-2.2" mutable="true" name="dal.Table1, dal, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="[Table1]">
    <id name="TestID" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="TestID" />
      <generator class="identity" />
    </id>
    <property name="Description" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="Description" not-null="true" />
    </property>
    <property name="TestDate" type="date">
      <column name="TestDate" not-null="true" />
    </property>
  </class>
</hibernate-mapping>
log4net捕获的NHibernate日志条目的相关部分:

DEBUG2011-03-24 05:00:18 – SELECT table1x0_.TestID as TestID0_0_, table1x0_.Description as Descript2_0_0_, table1x0_.TestDate as TestDate0_0_ FROM [Table1] table1x0_ WHERE table1x0_.TestID=@p0;@p0 = 1
DEBUG2011-03-24 05:00:18 – UPDATE [Table1] SET Description = @p0, TestDate = @p1 WHERE TestID = @p2;@p0 = 'Updated 3/24/2011 5:00:18 PM', @p1 = NULL, @p2 = 1
DEBUG2011-03-24 05:00:18 – Building an IDbCommand object for the SqlString: UPDATE [Table1] SET Description = ?, TestDate = ? WHERE TestID = ?
DEBUG2011-03-24 05:00:18 – Dehydrating entity: [dal.Table1#1]
DEBUG2011-03-24 05:00:18 – binding 'Updated 3/24/2011 5:00:18 PM' to parameter: 0
DEBUG2011-03-24 05:00:18 – binding '6/12/1700' to parameter: 1
DEBUG2011-03-24 05:00:18 – binding '1' to parameter: 2
DEBUG2011-03-24 05:00:18 – Obtaining IDbConnection from Driver
ERROR2011-03-24 05:00:19 – Could not execute command: UPDATE [Table1] SET Description = @p0, TestDate = @p1 WHERE TestID = @p2
System.Data.SqlClient.SqlException (0x80131904): Cannot insert the value NULL into column 'TestDate', table 'test2.dbo.Table1'; column does not allow nulls. UPDATE fails.
The statement has been terminated.
   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)
   at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning()
   at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
   at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
   at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async)
   at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result)
   at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(DbAsyncResult result, String methodName, Boolean sendToPipe)
   at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
   at NHibernate.AdoNet.AbstractBatcher.ExecuteNonQuery(IDbCommand cmd)
日志似乎显示了值“6/12/1700”与日期列参数的正确绑定,但SQL语句抛出异常,表示它正在尝试插入NULL。如果记录中的值大于“1/1/1753”,则不存在异常,并且该值被正确保留

我可以发布完整的NHibernate日志文件,如果其中有更多信息可能会有所帮助。我不知道从这里到哪里去找答案

有没有人想过在哪里寻找解决方案

提前感谢,


~Jim Fennell

对不起,我刚刚意识到我应该把这篇文章作为问题的答案,而不是仅仅评论。。。请不要嘲笑“新来的家伙!”


通过进一步的讨论和测试,这个问题似乎和ADO.NET和NHibernate对MS SQL 2008数据类型Date列使用DbType.Date有关。如果代码使用SqlDbType.Date而不是DbType.Date,则不会发生此类问题,并且所有操作都将按照指定的方式执行

虽然DbType.Date的使用对于其他数据库类型来说似乎更“可移植”,但它确实引入了这个问题,因为ADO.NET DbType.Date的最小值为1/1/1753

解决这个问题的一个方法是告诉NHibernate列的类型是DATETIME2,它还支持早于1/1/1753的日期值。如果NHibernate映射为:

<property name="TestDate" type="datetime2">
  <column name="TestDate" sql-type="date" />
</property>

代码按预期执行,没有异常

很遗憾,NHibernate没有意识到它使用的是MSSQLS2008方言,并且使用的是SqlDbTypes,而不是DbTypes,但是这种解决方法目前似乎还有效

有关ADO.NET方面的更多信息,请参阅。感谢@Graham Bunce在这方面的帮助


我希望这些信息能帮助将来遇到这个问题的任何人

将FluentNHibernate与NHibernate 2.1一起使用时,这适用于SQL Server 2008 R2:

public class TestMap : Map<TestMap> {
    Map(x => x.DateStart).CustomType("datetime2");
}
公共类TestMap:Map{
Map(x=>x.DateStart).CustomType(“datetime2”);
}

我仍然没有找到对此的任何解释。我开始怀疑这是NHibernate中的一个bug。是否有其他人在使用SQL 2008日期值小于最小日期时间值时遇到类似问题?如果您正在成功更新小于1/1/1753的日期值(未将其更改为null),您是否愿意通过进一步的讨论和测试,为相关列和表共享我们的映射和模型文件的代码片段,现已确定,此问题与ADO.NET和NHibernate对数据类型为Date的MS SQL 2008列使用DbType.Date有关。如果代码使用SqlDbType.Date而不是DbType.Date,则不会发生此类问题,并且所有操作都将按照指定的方式执行。虽然DbType.Date的使用对于其他数据库类型来说似乎更“可移植”,但它确实引入了这个问题,因为ADO.NET DbType.Date的最小值为1/1/1753。对于我来说,这并不能解决SQL Server Express(实际上是SQL Server 2008,使用相同的方言等)的问题。有点奇怪,
Map(pn=>pn.DateStart).CustomType();
给了我一个
没有为这个对象定义无参数构造函数。
和上面Ivan的代码对我很有用,尽管时间总是在2014-01-13 XX:XX:XX.XXX3843格式(最后总是3843)。使用Timestamp自定义类型将最后四位数字归零,因此我不确定最佳组合(哪个CustomType、Timestamp或DateTime2,SQL Server中的哪个列类型(DateTime或DateTime2))是什么。
public class TestMap : Map<TestMap> {
    Map(x => x.DateStart).CustomType("datetime2");
}