Защита критических разделов на основе условия в C # - PullRequest
2 голосов
/ 26 мая 2010

Я имею дело с курьезным сценарием.

Я использую EntityFramework для сохранения (вставки / обновления) в базу данных SQL в многопоточной среде. Проблема в том, что мне нужно получить доступ к базе данных, чтобы увидеть, был ли уже создан регистр с определенным ключом, чтобы установить значение поля (выполняется), или он является новым для установки другого значения (в ожидании). Эти регистры идентифицируются уникальным путеводителем.

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

static readonly object LockableObject = new object();
static void SaveElement(Entity e)
{
       lock(LockableObject)
       {
           Entity e2 = Repository.FindByKey(e);
           if (e2 != null)
           {
               Repository.Insert(e2);
           }
           else
           {
               Repository.Update(e2);
           }
       }
}

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

Интересно, есть ли что-то подобное (пожалуйста, примите это просто как идею):

static void SaveElement(Entity e)
{
       (using ThisWouldBeAClassToProtectBasedOnACondition protector = new ThisWouldBeAClassToProtectBasedOnACondition(e => e.UniqueId)
       {
           Entity e2 = Repository.FindByKey(e);
           if (e2 != null)
           {
               Repository.Insert(e2);
           }
           else
           {
               Repository.Update(e2);
           }
       }
}

Идея заключалась бы в том, чтобы иметь вид защиты, который защищал бы в зависимости от условия, поэтому каждый объект e имел бы собственную блокировку на основе свойства e.UniqueId.

Есть идеи?

Ответы [ 2 ]

1 голос
/ 26 мая 2010

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

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

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

0 голосов
/ 26 мая 2010

Это может работать для вас, вы можете просто заблокировать экземпляр e:

   lock(e)
   {
       Entity e2 = Repository.FindByKey(e);
       if (e2 != null)
       {
           Repository.Insert(e2);
       }
       else
       {
           Repository.Update(e2);
       }
   }
...