powered by simpleCommunicator - 2.0.51     © 2025 Programmizd 02
Форумы / ADO.NET, LINQ, Entity Framework, NHibernate, DAL, ORM [игнор отключен] [закрыт для гостей] / Обработка конкурентного доступа (StaleObjectStateException) в БД используя NHibernate
2 сообщений из 2, страница 1 из 1
Обработка конкурентного доступа (StaleObjectStateException) в БД используя NHibernate
    #37502870
midavik
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Добрый день! Ищю совета как правильно обработать ситуацию конкурентного доступа к записи в БД двумя пользователями при использовании в качестве посредника NHibernate для работы с БД.

Есть таблица в БД MSSQL Server-e 2005

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
<class name="Customer" optimistic-lock="version" dynamic-update="true">
    <id name="Id" type="int" unsaved-value="0">
      <generator class="identity"/>
    </id>

    <version name="Version"/>
    <property name="FullName" length="30" />
    <property name="Position" />
 </class>

Для обнаружения конфликта при параллельном доспупе к записи в таблице БД использую optimistic-lock="version" в маппинге и соответственно такое же поле в объекте Customer.

Сессия NHibernate в проекте используется одна долгоживущяя для всех форм (объектов).

По адрессу http://msdn.microsoft.com/ru-ru/magazine/ee819139.aspx на русском
http://msdn.microsoft.com/en-us/magazine/ee819139.aspx на английском
нашел пример обрабоки ситуации при возникновении конфликта при параллельном изменениии записи двумя пользователями, так вот там рекомендуется если нужно при конфликте просто сохранить в БД свою версию записи, то нужно всего навсего получить
текущее значение поля Version из таблицы БД и присвоить его своему объекту и далее сохранить уже свой объект в БД. Правда в примере для сохранения изменений в объекте используется отдельная сессия NHibernate.

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
...
dbVersionCustomer = GetById(customer.Id, true);
// допустим dbVersionCustomer.Version равно 5
// а customer.Version равно 4
if (dbVersionCustomer != null) customer.Version = dbVersionCustomer.Version;
Merge(customer);
Commit();
// теперь после подверждения изменений в БД в поле Version будет значение 6
// но в самом объекте в приложении почему-то старое значение 5
...

Все вроде бы работает, но в БД записываются нужные измениния с правильном зачением поля Version,
а в объекте customer поле Version имет старое значение.

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
public void UpdateEntity(Customer customer)
{
   BeginTransaction();
   {
	   try
	   {
		   if (customer.Id != null || customer.Id > 0)
		   {
			   Merge(customer);
			   Commit();  
			   // После подверждения транзации значение поля customer.Version
			   // НЕ увеличивается на единицу в объекте customer, а в таблице БД увеличивется
                           // Таким образом значения поля Version будут разными в объекте и таблице БД
		   }
		   else
			   SaveOrUpdate(customer, true);
	   }
	   catch (Exception ex)
	   {
		   if (ex is StaleObjectStateException)
		   {
			   try
			   {
				   Rollback();
				   Customer dbVersionCustomer;

				   if (DialogResult.Yes == MessageBox.Show("Another client was updated this field." +
														   "\nPress button \"OK\" to insert your version to the DB !", "Information",
														   MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation))
				   {
					   try
					   {
						   BeginTransaction();
						   dbVersionCustomer = GetById(customer.Id, true);
						   if (dbVersionCustomer != null) customer.Version = dbVersionCustomer.Version;
						  
						   dbVersionCustomer = null;
						   Merge(customer);
						   Commit();
						   // После подверждения транзации значение поля customer.Version
						   // НЕ увеличивается на единицу в самом объекте customer,
						   // а вот в БД записывается правильное значение
                                                   // Таким образом значения поля Version будут разными в объекте и таблице БД
					   }
					   catch (Exception e)
					   {
						   Rollback();
						   throw ex;
					   }
				   }
			   }
			   catch (Exception ex)
			   {
				   Rollback();
				  throw ex;
			   }
		   }
		   else throw ex;
	   }
   }
}

Теперь если после обработки исключения StaleObjectStateException и принятия решения сохранить свою версию в БД, пользователь через некоторое время вновь сделает изменения в этом объекте и решит сохранить их в БД (второй пользователь ничего не изменял) то опять будет сгенерировано исключение StaleObjectStateException, т.к. в объекте было одно значение в поле Version, а в таблице БД другое.

В общем интересует мнение знающих как правильно разрулить эту ситуацию или вообще как правильно обрабатывать ситуацию с конкурентным доступом.

Да, методы
Код: plaintext
1.
BeginTransaction(); Merge(customer); Commit();  SaveOrUpdate(customer, true); 
GetById(customer.Id, true); Rollback();
- это все обертки над методами сессии NHibernate:
...
Рейтинг: 0 / 0
Обработка конкурентного доступа (StaleObjectStateException) в БД используя NHibernate
    #37508117
SolYUtor
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
midavik,

Не знаю, как вы там обрабатываете исключение, но вкратце правила таковы:
1. После возникновения StaleObjectStateException сессия переходит в неопределённое состояние, и в ответ на любые действия будет кидаться исключениями.
2. Merge сливает изменения из вашего объекта из дохлой сессии, в объект загруженный в рамках новой сессии. После этого объект загруженный в дохлой сессии использовать нельзя, а использовать свежезагруженный и смерженный.
...
Рейтинг: 0 / 0
2 сообщений из 2, страница 1 из 1
Форумы / ADO.NET, LINQ, Entity Framework, NHibernate, DAL, ORM [игнор отключен] [закрыт для гостей] / Обработка конкурентного доступа (StaleObjectStateException) в БД используя NHibernate
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]