Свободные проблемы NHibernate со значениями столбца DATE в SQL Server 2008 - PullRequest
9 голосов
/ 25 марта 2011

Привет,

У меня проблемы с использованием столбца SQL Server 2008 DATE в C # с использованием Fluent NHibernate.

Когда я пытаюсь обновить запись со значением в столбце DATE, который не имеет значения NULL, до 01.01.1753 (минимальная дата для DATETIME), я получаю сообщение об ошибке, сообщающее, чтоон не может вставить 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, 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>

Записи журнала NHibernate.SQL, захваченные log4net:

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

Соответствующий раздел записей журнала NHibernate, захваченных log4net:

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' к параметру для столбца DATE, но оператор SQL выдает исключение, говорящее, что он пытается вставить NULL.Если значение в записи больше, чем «1/1/1753», исключений нет, и значение сохраняется правильно.

Я могу опубликовать полный файл журнала NHibernate, если там будет больше информацииэто может помочь.Я не уверен, где искать ответ здесь.

У кого-нибудь есть мысли о том, где искать решение?

Заранее спасибо,

~Джим Феннелл

Ответы [ 2 ]

12 голосов
/ 31 марта 2011

Извините, только что понял, что я должен опубликовать это как ответ на вопрос, а не просто комментировать ... Пожалуйста, не смейтесь над "новым парнем!"

В ходе дальнейших обсуждений и тестирования кажется, что эта проблема связана с ADO.NET и использованием NHibernate столбца DbType.Date для MS SQL 2008 типа данных DATE. Если бы код использовал SqlDbType.Date вместо DbType.Date, таких проблем не возникало, и все работало бы так, как указано.

Хотя использование DbType.Date может показаться более «переносимым» для других типов баз данных, оно создает эту проблему, поскольку для ADO.NET DbType.Date установлено минимальное значение 1/1/1753.

Временное решение этой проблемы - сообщить NHibernate, что тип столбца - DATETIME2, который также поддерживает значения даты более ранние, чем 01.01.1753. Если отображение NHibernate:

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

Код работает, как и ожидалось, без исключений.

Жаль, что NHibernate не распознает, что использует диалект MsSql2008, и использует SqlDbTypes, а не DbTypes, но этот обходной путь пока работает.

Для получения дополнительной информации об аспектах ADO.NET см. Сбой при вставке минимального значения ADO.NET в SQL Server 2008 Date . Спасибо @Graham Bunce за помощь в этом.

Я надеюсь, что эта информация поможет любому, кто столкнется с этой проблемой в будущем.

2 голосов
/ 18 марта 2013

При использовании FluentNHibernate с NHibernate 2.1 это работает с SQL Server 2008 R2:

public class TestMap : Map<TestMap> {
    Map(x => x.DateStart).CustomType("datetime2");
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...