2015-04-14 5 views
0

В моем проекте C# у меня есть метод, который спрашивает, существует ли объект в db, а если нет, то создает его. Теперь, если два пользователя задают один и тот же вопрос одновременно, оба они получают нуль, поэтому поток будет сохранять в db, что невозможно для двух дубликатов, чтобы сделать это, поэтому вызовет исключение sql. Как я могу справиться с этой проблемой, пожалуйста?C# одновременные вызовы для sql db

вот мой код:

var date = DateTime.UtcNow.Date; 


var todayCelebPageView = _celebPageViewsRepo.GetAll().SingleOrDefault(d => d.iCelebId == celebId && d.dDate == date); 

if (todayCelebPageView != null) 
{ 
    todayCelebPageView.iScore++; 

    _celebPageViewsRepo.Save(); 
} 
else 
{ 
    todayCelebPageView = new MovliCelebPageView() {dDate = date, iCelebId = celebId, iScore = 1}; 
    _celebPageViewsRepo.Add(todayCelebPageView); 
    _movliRepository.DbContext.Entry(todayCelebPageView).State = System.Data.EntityState.Added; 
    _celebPageViewsRepo.Save(); 
} 
+0

Поймать исключение – stuartd

ответ

2

Там нет простого ответа на это на самом деле, это общая проблема с целым рядом решений.

Некоторые опции могут быть:

  1. Поймать правильное исключение SQL, и повторно попытаться соответственно
  2. Создайте очередь для тех вызовов базы данных и обрабатывать их по одному
  3. Некоторые реализации блокировки, либо в базе данных (возможно, путем ее переноса в транзакции), либо в самом коде.

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

Должен ли человек, который создал запись, в последний раз выиграть? Если первый человек победит, а второй получит ошибку? Или вы должны написать первую запись и обновить ее со второй?

Ответ на этот вопрос полностью зависит от специфики того, что вы пытаетесь сделать в своем приложении.

+0

Должен ли я использовать объект блокировки в этом случае? –

0

Переместить логику проверки и создать на уровень процедуры, то он будет обработан с изолированностью транзакций:

IF NOT EXISTS (SELECT 'non-empty' FROM sys.objects WHERE object_id = OBJECT_ID(N'dbo.TABLE_NAME') AND type in (N'U')) 
    CREATE TABLE dbo.TABLE_NAME 

Но вам все равно придется обернуть свой метод и обрабатывать исключения в соответствии с Number свойства SqlException :

using (SqlConnection connection = new SqlConnection(connectionString)) 
{ 
    SqlCommand command = new SqlCommand(queryString, connection); 
    try 
    { 
     command.Connection.Open(); 
     command.ExecuteNonQuery(); 
    } 
    catch (SqlException ex) 
    { 
     for (int i = 0; i < ex.Errors.Count; i++) 
     { 
      errorMessages.Append("Index #" + i + "\n" + 
       "Message: " + ex.Errors[i].Message + "\n" + 
       "LineNumber: " + ex.Errors[i].LineNumber + "\n" + 
       "Source: " + ex.Errors[i].Source + "\n" + 
       "Procedure: " + ex.Errors[i].Procedure + "\n"); 
     } 
     Console.WriteLine(errorMessages.ToString()); 
    } 
} 

System Error Messages
Cause and Resolution of Database Engine Errors

0

Вы должны перенести тест на существование и вставить в транзакцию. Таким образом, второй вызов для проверки существования будет блокироваться, пока первый будет завершен.

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