Как я могу сказать NHibernate, чтобы сохранить только измененные свойства

У меня есть класс Person, сопоставленный с базой данных с помощью NHibernate. Я загружаю объекты из БД и отправляю их разным клиентам. Первый клиент изменит имя и страну. Второй клиент будет изменять только свойство Name. Затем оба возвращают измененные объекты на сервер. Когда я сохраняю данные из первого клиента - затем сохраняю правильно, и имя, и страна обновляются. Когда я сохраняю данные из второго клиента - у меня проблема. Это было переопределить данные от первого клиента и сохранить новое имя и начальное значение страны.

Как я могу сказать NHibernate, чтобы сохранить только значение имени, а не переопределить значение страны?

public class Person
{
    public string Name { get; set; }
    public string Country { get; set; }
}

public static List<Person> GetEntities()
{
    var factory = CreateSessionFactory();
    using (ISession session = factory.OpenSession())
    {
        return session.CreateCriteria<Person>().List<Person>();                
    }
}

public static void SaveEntities(List<Person> entities)
{
    var factory = CreateSessionFactory();
    using (ISession session = factory.OpenSession())
    {
         using (var t = session.BeginTransaction())
         {
             foreach (var person in entities)
             {
                 session.Merge(person);
             }

             t.Commit();
        }
    }
}

PS: извините за мой плохой английский

4 ответа

Решение

Ответ: ты не можешь. NH не знает, что изменилось только имя.

Вы можете избежать этого, не допуская одновременного редактирования. Например, оптимистичным механизмом блокировки NH. Второй клиент получит StaleObjectStateException,

Если редактирование двух клиентов на самом деле происходит не одновременно (но оба они основаны на одном и том же состоянии объекта), необходимо убедиться, что второй клиент получает изменения первого перед редактированием. Например, путем получения фактического состояния перед открытием редактора или путем отправки измененного уведомления с сервера.

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

На самом деле, вы можете сказать NHibernate специально обновить "грязные" поля, используя Dynamic Update,

Подробнее: http://ayende.com/blog/3946/nhibernate-mapping-concurrency

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

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

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

Когда вы создаете отображение вашего объекта в nhibernate, все данные, присутствующие в этих объектах, будут сохраняться (или обновляться) в базе данных после сброса сеанса. Вы не можете назначить отдельные поля для обновления, это все или ничего.

Еще один (не связанный) момент, ваш пример кода создает новую фабрику сеансов для каждой операции вашей сущности. Как правило, это плохая идея, поскольку фабрики сессий стоят дорого. Вам лучше управлять фабрикой сессий через глобальный контекст (синглтон), создавать его один раз и создавать сеансы (которые имеют меньший вес), когда это необходимо.

Другие вопросы по тегам