2013-11-15 2 views
0

У меня возникли проблемы с реализацией optimisitc-параллелизма в NHibernate значимым образом в веб-приложении. Вот желаемый сценарий:Оптимистическая параллелизм вне сессии в NHibernate

  1. Пользователь А открывает форму для редактирования записи
  2. пользователя B открывает ту же форму для редактирования той же записи
  3. Пользователь A Сохраняет свои данные
  4. Пользователь B пытается сохраните их данные, но получите предупреждение о том, что данные были обновлены.

Общий сценарий. Вот обновление кода и объект отображение файл:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="Entities" assembly="Domain"> 
    <class name="Record" /> 
     <id name="Id" column="Id" type="long"> 
      <generator class="identity"/> 
     </id> 
     <version name="Version" column="Version" type="datetime" /> 
     <property name="Description" column="`Description`" type="string" /> 
    </class> 
</hibernate-mapping> 

public void Edit(int id, string description, DateTime version) 
{ 
    using (var session = sessionFactory.OpenSession()) 
    using (var tx = session.BeginTransaction()) 
    { 
    var record = session.Get<Record>(id); 
    record.Version = version; 
     record.Description = description; 
     session.Update(record); 
    tx.Commit(); 
    } 
} 

Значение версии загружаются, когда пользователь открывает форму и хранится в скрытом поле. Я надеялся, что NHibernate попытается обновить версию из формы в предложении WHERE, но вместо этого использует значение, которое оно только что загрузило в сеанс.

Другие вещи, которые я прочитал, говорят мне, что я должен сравнивать значения и (например) вызывать исключение, если он загружает более новую версию. Но я не могу поверить, что есть лучший способ.

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

Я хочу, чтобы иметь возможность вручную устанавливать версию в зависимости от того, что было в форме, когда пользователь первоначально загрузил ее. Это возможно? Или я чего-то не хватает?

ответ

0

Ответ здесь:

Я надеялся, что NHibernate попытается обновить с версии от формы в ИНЕКЕ, но вместо этого он использует значение, которое он только что загруженную в сессии.

NHibernate будет делать, точно/и только то, к чему мы явно обращаемся. Другие слова. Как NHibernate может узнать о скрытом поле в форме? веб-форму? выиграть форму? ...

Итак, хитрость заключается в том, что мы должны установить назад значение, посланное от клиента, и связывает его версию. Просто пример. Я предпочитаю Timestamps, сгенерировано автоматически byte[] значения. Таким образом, в то время как мое отображение и свойство выглядит следующим образом:

<version name="Timestamp" generated="always" unsaved-value="null" type="BinaryBlob"> 
    <column name="RowVersion" not-null="false" sql-type="timestamp"/> 
</version> 

и эти два C# свойство объекта:

protected virtual byte[] Timestamp { get; set; } 
public virtual string Version 
{ 
    get { return Timestamp.IsEmpty() ? null : Convert.ToBase64String(Timestamp); } 
    set { Timestamp = value.IsEmpty() ? null : Convert.FromBase64String(value); } 
} 

Итак, теперь, «скрытое» поле клиента может содержать строковое значение Version свойства. После отправки на сервер/уровень данных:

  1. Объект, который будет отредактировать, загружается NHibernate в Session. в настоящий момент, его Version/Timestamps действительно отражает загруженное состояние из БД.Итак:
  2. мы должны привязать значение, исходящее от клиента (скрытое поле) .. и заменить свежее/только что загруженное значение из БД.

И теперь все работает, точно так, как ожидалось ... даже в многопользовательской среде (веб)

0

Я знаю, что это старый вопрос, но я оставлю свой обычный подход здесь.

Это проблема с «проблемами» при использовании ORM. «NHibernate» и «Entity Framework» страдают этой «проблемой», и это происходит из-за того, что ORM отслеживает внутреннее значение версии, а не использует значение, возвращаемое свойством. В отличие от EF, где вы можете скопировать значения byte[] с использованием Array.Copy, в NHibernate I обычно выселении лица из сессии, а затем сделать обновление, которое указывает на NHibernate, что вы обновляете существующий объект, но он начнет отслеживать с помощью версии просто назначенную

Вот фрагмент кода:.

public void Edit(int id, string description, DateTime version) 
{ 
    using (var session = sessionFactory.OpenSession()) 
    using (var tx = session.BeginTransaction()) 
    { 
     var record = session.Get<Record>(id); 
     record.Version = version; 
     record.Description = description; 

     session.Evict(record); // evict the object from the session 
     session.Update(record); // NHibernate will attach the object, and will use your version 

     tx.Commit(); 
    } 
} 

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

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

Смежные вопросы