Как вставить или обновить (или перезаписать) запись с помощью NHibernate? - PullRequest
12 голосов
/ 28 ноября 2008

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

В NHibernate решения, которые я нашел, требуют загрузки сущности и ее изменения или удаления сущности, чтобы можно было вставить новую. Приложение должно заботиться, если запись уже существует. Есть ли способ обойти это?

Имеет ли значение Id?

Назначенный идентификатор

Объект имеет ключевое слово в качестве назначенного идентификатора и является первичным ключом в таблице.

Я понимаю, что SaveOrUpdate () будет вызывать методы Save () или Update () в зависимости от ситуации на основе идентификатора. Используя назначенный идентификатор, это не будет работать, потому что идентификатор не является несохраненным значением. Однако поле Version или Timestamp можно использовать вместо индикатора. В действительности это не имеет значения, потому что это отражает только то, был ли объект в памяти связан с записью в базе данных; он не указывает, существует ли запись в базе данных или нет.

Сгенерированный идентификатор

Если бы назначенный идентификатор действительно был причиной проблемы, я мог бы использовать сгенерированный идентификатор вместо ключевого слова в качестве первичного ключа. Это позволило бы избежать проблемы вставки / обновления NHibernate, поскольку она всегда вставлялась бы эффективно. Тем не менее, я все еще должен предотвратить дублирование ключевых слов. С уникальным индексом для столбца ключевого слова он все равно выдаст исключение для дублированного ключевого слова, даже если первичный ключ отличается.

Другой подход?

Возможно, проблема не в NHibernate, а в том, как это моделируется. В отличие от других областей приложения, это больше ориентировано на данные, чем на объект. Приятно, что NHibernate облегчает чтение / запись и устраняет хранимые процедуры. Но желание просто писать без учета существующих ценностей не вписывается в модель модели идентичности объекта. Есть ли лучший способ приблизиться к этому?

Ответы [ 6 ]

7 голосов
/ 27 января 2009

Я использую

    public IList<T> GetByExample<T>(T exampleInstance)
    {
        return _session.CreateCriteria(typeof(T))
                    .Add(Example.Create(exampleInstance))
                    .List<T>();
    }

    public void InsertOrUpdate<T>(T target)
    {
        ITransaction transaction = _session.BeginTransaction();
        try
        {
            var res=GetByExample<T>(target);
            if( res!=null && res.Count>0 )
                _session.SaveOrUpdate(target);
            else
               _session.Save(target); 
            transaction.Commit();
        }
        catch (Exception)
        {
            transaction.Rollback();
            throw;
        }
        finally
        {
            transaction.Dispose();
        }
    }

но метод FindByExample возвращает все объекты, а не объекты с точным идентификатором. Что вы предлагаете? так как у меня есть только объект в качестве параметра, у меня нет доступа к его конкретному полю ID, поэтому я не могу использовать session.get(Object.class(), id);

6 голосов
/ 05 февраля 2009

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

http://web.archive.org/web/20090831032934/http://devlicio.us/blogs/mike_nichols/archive/2008/07/29/when-flushing-goes-bad-assigned-ids-in-nhibernate.aspx

0 голосов
/ 27 сентября 2018

Запрос объектов, где ключевое слово = x, возьмите FirstOrDefault. Если это значение равно null, добавьте новый объект, если он существует, обновите полученный объект и вызовите для него saveOrUpdate.

0 голосов
/ 28 ноября 2008

Вы можете сделать

Obj j = session.get(Object.class(), id);
if (j != null)
   session.merge(myObj);
else
   session.saveOrUpdate(myObj);
0 голосов
/ 28 ноября 2008

Используйте метод session.SaveOrUpdate (object).

0 голосов
/ 28 ноября 2008

вызовите hibernate.saveOrUpdate (), который проверит, находится ли объект в базе данных, обновит его, если он есть, и сохранит (т.е. вставит), если это не так.

...