NHibernate Session.Flush () Отправка запросов на обновление, если обновление не произошло - PullRequest
34 голосов
/ 29 августа 2008

У меня есть сеанс NHibernate. В этом сеансе я выполняю ровно 1 операцию, которая заключается в запуске этого кода для получения списка:

public IList<Customer> GetCustomerByFirstName(string customerFirstName)
{
return _session.CreateCriteria(typeof(Customer))
    .Add(new NHibernate.Expression.EqExpression("FirstName", customerFirstName))
    .List<Customer>();
}

Я звоню Session.Flush() в конце HttpRequest, и я получаю HibernateAdoException. NHibernate передает инструкцию обновления в базу данных и вызывает нарушение внешнего ключа. Если я не запускаю flush, запрос завершается без проблем. Проблема здесь в том, что мне нужен сброс в случае, если есть изменения, которые происходят в других сеансах, так как этот код повторно используется в других областях. Возможно, мне не хватает другого параметра конфигурации?


Вот код из исключения:

[SQL: UPDATE CUSTOMER SET first_name = ?, last_name = ?, strategy_code_1 = ?, strategy_code_2 = ?, strategy_code_3 = ?, dts_import = ?, account_cycle_code = ?, bucket = ?, collector_code = ?, days_delinquent_count = ?, external_status_code = ?, principal_balance_amount = ?, total_min_pay_due = ?, current_balance = ?, amount_delinquent = ?, current_min_pay_due = ?, bucket_1 = ?, bucket_2 = ?, bucket_3 = ?, bucket_4 = ?, bucket_5 = ?, bucket_6 = ?, bucket_7 = ? WHERE customer_account_id = ?]

Параметры не отображаются как переданные.

Ответы [ 3 ]

45 голосов
/ 16 сентября 2009

Всегда будьте осторожны с пустыми полями, когда вы имеете дело с NHibernate. Если ваше поле NULLable в БД, убедитесь, что соответствующий класс .NET также использует тип Nullable. Иначе произойдут все странные вещи. Симптом обычно заключается в том, что NHibernate будет пытаться обновить запись в БД, даже если вы не изменили никаких полей с момента чтения сущности из базы данных.

Следующая последовательность объясняет, почему это происходит:

  1. NHibernate извлекает необработанные данные сущности из БД, используя ADO.NET
  2. NHibernate создает сущность и устанавливает ее свойства
  3. Если поле БД содержало NULL, для свойства будет установлено значение по умолчанию для его типа:
    • свойства ссылочных типов будут установлены в нуль
    • свойства целочисленных типов и типов с плавающей запятой будут установлены в 0
    • свойства логического типа будут установлены в false
    • свойства типа DateTime будут установлены в DateTime.MinValue
    • и т.д.
  4. Теперь, когда транзакция зафиксирована, NHibernate сравнивает значение свойства с исходным значением поля, которое оно считывает из формы DB, и поскольку поле содержит NULL, но свойство содержит ненулевое значение, NHibernate рассматривает свойство грязный, и вынуждает обновление объекта.

Мало того, что это снижает производительность (вы получаете дополнительное двустороннее обращение к БД и дополнительное обновление каждый раз, когда извлекаете сущность), но это также может вызвать проблемы с устранением ошибок в столбцах DateTime. Действительно, когда свойство DateTime инициализируется значением по умолчанию, оно устанавливается на 1/1/0001. Когда это значение сохраняется в БД, SqlClient ADO.NET не может преобразовать его в действительное значение SqlDateTime, поскольку наименьшее возможное значение SqlDateTime составляет 1/1/1753 !!!

Самое простое решение - заставить свойство класса использовать тип Nullable, в данном случае «DateTime?». В качестве альтернативы, вы могли бы реализовать собственный преобразователь типов, реализовав IUserType с его методом Equals, надлежащим образом сравнивая DbNull.Value с любым значением по умолчанию вашего типа значения. В нашем случае Equals необходимо будет возвращать true при сравнении 1/1/0101 с DbNull.Value. Реализация полнофункционального IUserType на самом деле не так сложна, но она требует знания пустяков NHibernate, поэтому приготовьтесь к существенному поиску в Google, если вы решите пойти по этому пути.

16 голосов
/ 29 августа 2008

Я видел это однажды, когда одна из моих моделей не была правильно отображена (неправильно использовались обнуляемые типы). Можете ли вы вставить свою модель и карту?

0 голосов
/ 18 июля 2009

Я также столкнулся с этой проблемой в NH 2.0.1, когда пытался скрыть обратные концы пакетов «многие ко многим», используя access = "noop" (подсказка: это не работает).

Преобразование их в access = "field" + добавление поля в классе решило проблему. Довольно сложно отследить их, хотя.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...