使用Fluent NHibernate在C#中使用sql Server 2008 DATE列时遇到问题.
当我尝试更新在1/1/1753(DATETIME的最小日期)之前的不可为空的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"); } }
正在执行的代码:
using (DBSess sess = DBSess.Create()) { Table1 tbl = dal.Table1.Load(sess,1); tbl.Description = String.Format("Updated {0}",DateTime.Now); tbl.Save(sess); sess.Commit(); }
导出的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,PublicKeyToken=b77a5c561934e089"> <column name="TestID" /> <generator class="identity" /> </id> <property name="Description" type="System.String,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.sql日志条目:
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
log4net捕获的NHibernate日志条目的相关部分:
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,Boolean returnStream,Boolean async) at System.Data.sqlClient.sqlCommand.RunExecuteReader(CommandBehavior cmdBehavior,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”与DATE列的参数的正确绑定,但sql语句引发了一个异常,表示它试图插入一个NULL.如果记录中的值大于“1/1/1753”,则不会有异常,并且该值正确保存.
我可以发布完整的NHibernate日志文件,如果有更多的信息可能有帮助.我不知道从哪里来看这个答案.
有没有人有任何想法在哪里寻找解决方案?
提前致谢,
〜吉姆·芬内尔
解决方法
通过进一步的讨论和测试,似乎这个问题与ADO.NET和NHibernate对数据类型DATE的MS sql 2008列的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不能识别它正在使用Mssql2008方言,并使用sqlDbTypes而不是DbTypes,但这种变通方法现在可以工作.
有关ADO.NET方面的更多信息,请参阅ADO.NET Insert Min Value into SQL Server 2008 Date column crashes.感谢@Graham Bunce的帮助.
我希望这些信息有助于将来遇到这个问题的任何人.