2009-06-11 5 views
5

У меня возникли проблемы с сохранением объекта в базе данных SQL Server 2005. Я использую NHibernate 2.0.0.3002 для моего уровня сохранения. Отображение является типичным с идентификатором целого числа, следующим образом:Исключение NHibernate «null identifier» после вставки объекта

<id name="Id" unsaved-value="0"> 
    <column name="Id"/> 
    <generator class="identity" /> 
</id> 

Я кратко опустил остальные для краткости. Приложение использует класс репозитория с универсальным способом сохранения следующим

public void Save(T toSave) 
{ 
    Save(new T[] { toSave }); 
} 

public void Save(IEnumerable<T> toSave) 
{ 
    using (ISession session = SessionFactory.OpenSession()) 
    { 
     foreach (T item in toSave) 
     { 
      session.SaveOrUpdate(item); 
     } 
     session.Flush(); 
    } 
} 

При вызове SaveOrUpdate на сессии, генерируется исключение с сообщением «нулевым идентификатором». Когда я проверяю базу данных, строка была вставлена ​​со всеми правильными значениями, поэтому я думаю, что проблема в том, что NHibernate пытается установить свойство Id объекта с значением, возвращаемым @@ IDENTITY. Я вижу через SQL Profiler, что @@ IDENTITY вызывается, поэтому я не понимаю, почему выбрано исключение.

У кого-нибудь еще была эта проблема?

+0

Можете ли вы показать код, который выполняет фактическое сохранение/обновление и когда вы пытаетесь использовать этот идентификатор? –

+0

Я добавил код в соответствии с запросом. – gilles27

+0

Какая версия NHibernate вы бежите кстати? –

ответ

8

Как Сохранить и Удалить должно произойти в сделке, и сделка должна совершаться в конце.

так:

public void Save(IEnumerable<T> toSave) 
{ 
    using (ISession session = SessionFactory.OpenSession()) 
    { 
     ITransaction transaction = Session.BeginTransaction(); 

     foreach (T item in toSave) 
     { 
      session.SaveOrUpdate(item); 
     } 

     transaction.Commit();   
     session.Flush(); 
    } 
} 

обратите внимание: вы хотите, чтобы обернуть, что в использовании и правильно откатить ... также, размещение которых вы открываете и совершение сделки будет иметь значение на основе ваш сценарий. Вы также должны закрыть транзакцию, когда вы закончите ...

Кроме того, можете ли вы уточнить, где происходит исключение? Похоже, вы сохраняете родителя, а потом ребенок бросает, потому что идентификатор родителя равен нулю? Или это действительно бросает на спасение родителя?

+0

Я обернул все это в транзакцию, как указано, с откатом, вызванным при вызове исключения. Это устранило мою проблему, спасибо. Запись имеет отношения с двумя другими записями, но они оба существуют (и поэтому имеют идентификаторы) задолго до создания этой записи, поэтому я не считаю, что это может быть связано с проблемой. Я удивлен, что обертывание всего этого в транзакции исправило его, но, возможно, мне нужно провести некоторое исследование лучших способов использования сеансов и транзакций NHibernate. Любые указатели приветствуются. – gilles27

+0

Там действительно нет лучшего способа, имхо. Все зависит от вашего конкретного дизайна. Как правило, у меня есть общие корни, которые определяют каскады для детей. Затем я завершу сохранение на уровне совокупности в транзакции. Например. Ответы есть комментарии, поэтому я бы сделал answer.AddComment (комментарий); answerRepository.Save (ответ). Мой новый любимый способ обертывания сохранения в транзакции происходит из источника FNH (старый) .... будет опубликован в бит. – Ben

+0

' public void Save (T entity) { InTransaction (() => Session.SaveOrUpdate (entity)); } private void WithinTransaction (Действие) { Операция ITransaction = Session.BeginTransaction(); попытка { деятельность(); transaction.Commit(); } catch (исключение) { сделка.Rollback(); бросок; } , наконец { transaction.Dispose(); } } ' – Ben

-2

я думаю, что вместо генератора класса = «identitiy» />

попытка генератора класса = «guid.comp»

+0

Я думаю, вы имеете в виду guid.comb, а не guid.comp. В любом случае это не сработает, так как я работаю с целым ключом, а не с GUID-ключом. – gilles27

+1

Хотя это не сработало в этом конкретном случае, это сработало для меня. Неплохой ответ – Batman

0

Идентичность довольно обескуражен разработчиками NHibernate .. главный вопрос мы столкнулись в что до тех пор, пока вы не промокните, вы не получите идентификатор. В вашем случае Int HiLo будет хорошей заменой.

Это, как говорится, я думаю, что вы на самом деле хотите, чтобы это сделать ...

<id name="Id" column="Id" unsaved-value="0"> 
    <generator class="identity"/> 
</id> 
+0

Я попытался использовать XML, показанный здесь, но проблема остается. Я думаю, что XML эквивалентен моему выше, просто немного более кратким. – gilles27

1

Это может быть полезно, чтобы настроить log4net, так что вы можете войти и посмотреть действия, которые делают NHibernate ...

я когда-то была проблема с NHibernate, используя Access, а также, и был в состоянии решить ее настраивая регистрацию, чтобы я мог точно определить причину проблемы.

Сообщение об ошибке, которое я получил, отличается от вашего, но this - это статья, в которой я описываю, как я решил свою проблему. Возможно, это может быть полезно для вас. :)

+0

Я использовал Profiler для проверки SQL, выполняемого NHibernate, и все это выглядит правильно. Он даже вызывает @@ IDENTITY для получения нового идентификатора записи, но после этого генерируется исключение. Просто, чтобы быть ясным, я использую SQL Server, а не Access. – gilles27

+0

Я думал, вы когда-то сказали в своем TS, что используете Access? В любом случае, хороший парень, чтобы понизить всех людей, которые пытались помочь вам, но не предоставили правильное решение ... –

+0

Прошу прощения, если я оскорбил вас, понизив ваш ответ. Однако я верю в дух этого сайта, что неправильные или вводящие в заблуждение ответы должны быть отклонены, чтобы лучший контент был наверху. Голосование за ваш ответ ни в коем случае не критично относится к вам или к сообщению в блоге, с которым вы связались. Спасибо, что пытались помочь. – gilles27

0

У меня также была эта ошибка, и решение заключалось в том, чтобы обернуть ее в транзакцию, как упоминал Бен. Однако я не смог получить код Ben и gilles27, возможно, потому, что я новичок в generics и NHibernate. Я создал несколько другую реализацию, которая работает (используя Fluent NHibernate v1.3):

 public static ISession LocalDbSession = null; 

    public static void Save<T>(T toSave) 
    { 
     using (var transaction = LocalDbSession.BeginTransaction()) 
     { 
      LocalDbSession.Save(toSave); 
      transaction.Commit(); 
      LocalDbSession.Flush(); 
     } 
    } 

    public static void Save<T>(IEnumerable<T> toSave) 
    { 
     using (var transaction = LocalDbSession.BeginTransaction()) 
     { 
      foreach (T item in toSave) 
      { 
       LocalDbSession.Save(item); 
      } 

      transaction.Commit(); 
      LocalDbSession.Flush(); 
     } 
    } 
Смежные вопросы