Asp.net - mvc5: linq, проблема с сохранением повторяющейся записи

Кодирую дневной счетчик. Таблица счетчиков базы данных пуста. Если кто-то является моим первым посетителем текущего дня, я добавляю запись в базу данных и устанавливаю counter = 1; После этого, когда другой посетитель посещает текущий день, я увеличиваю свой счетчик ++ и обновляю запись.

Итак, мои записи должны быть такими:

Дата: 2018-10-01 счетчик: 23

Дата: 2018-10-02 счетчик: 65

Дата: 2018-10-03 счетчик: 20

Дата: 2018-10-04 счетчик: 89

Моя проблема заключается в следующем: если на сайт приходят посетители в одно и то же время, linq сохраняет 2 записи за тот же день. Нравится:

Дата: 2018-10-01 счетчик: 23

Дата: 2018-10-02 counter: 1 // Первая запись: counter = 1

Дата: 2018-10-02 counter: 65 // Вторая запись: counter = 65

Дата: 2018-10-03 счетчик: 20

Дата: 2018-10-04 counter: 1 // Первая запись

Дата: 2018-10-04 counter: 89 // вторая запись

Дата должна быть уникальной. Как я могу решить эту проблему? Мой код ниже. Большое спасибо.

public static int IncreaseCounter_DailySiteVisitors()
    {
        int counter = 0;
        using (var context = new MyProjectEntities())
        {
            try
            {
                string format = "dd.MM.yyyy";
                DateTime Today = DateTime.Now;
                var obj = (from record in context.CounterDailySiteVisitor
                           where 
                           record.DateRecord != null 
                           && record.DateRecord.HasValue 
                           && record.DateRecord.Value.Year == Today.Year 
                           && record.DateRecord.Value.Month == Today.Month
                           && record.DateRecord.Value.Day == Today.Day
                           select record).FirstOrDefault();



               //var obj = context.CounterDailyVisitor.Where(x => x.DateRecord != null && ((DateTime)x.DateRecord).ToString("yyyy.MM.dd") == DateTime.Now.ToString("yyyy.MM.dd")).FirstOrDefault();
                if (obj != null)
                {
                    counter = obj.Count ?? 0;
                    counter++;
                    obj.Count = counter;
                    context.SaveChanges();
                }
                else
                {
                    var newRecordObj = context.CounterDailySiteVisitor.Create();
                    newRecordObj.Count = 1;
                    newRecordObj.DateRecord = Today;
                    context.CounterDailySiteVisitor.Add(newRecordObj);
                    context.SaveChanges();
                }
            }
            catch (Exception e)
            {

            }


        }
        return counter;
    }

если это проблема параллелизма, в которой я не уверен на 100%, но если это так, добавьте блокировку ... вокруг этого процесса

Seabizkit 31.10.2018 14:55
0
1
155
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Lock имеет собственный набор проблем, если вы планируете использовать веб-ферму или запускать несколько экземпляров этого приложения MVC.

Ответ принят как подходящий

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

Что-то вроде ниже ...

public static int IncreaseCounter_DailySiteVisitors()
{
    private readonly object somethingObject = new object();

    var context = new MyProjectEntities() 

    var today = DateTime.Now;
    var todaysRecord = context.CounterDailyVisitor
                .SingleOrDefault(x => x.DateRecord.Year == Today.Year
                            && x.DateRecord.Month == Today.Month
                           && x.DateRecord.Day == Today.Day
                );
    if (todaysRecord != null)
    {
       //the existing count + 1
       todaysRecord.Count = todaysRecord.Count++;
    }
    else
    {

       Lock(somethingObject)
       {
           //recheck
           var todaysRecord = context.CounterDailyVisitor
                   .SingleOrDefault(x => x.DateRecord.Year == Today.Year
                       && x.DateRecord.Month == Today.Month
                    && x.DateRecord.Day == Today.Day
                );

           if (todaysRecord != null)
           {
               //the existing count + 1
               todaysRecord.Count = todaysRecord.Count++;
           }
           else
           {
            var newRecordObj = new CounterDailyVisitor();
            newRecordObj.Count = 1;
            newRecordObj.DateRecord =  DateTime.Now; //this shouldnt be nullable

            context.CounterDailySiteVisitor.Add(newRecordObj);
           }    
        }
    }
    context.SaveChanges();
}

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