Как запретить нескольким пользователям обновлять записи одновременно с помощью LINQ - PullRequest
0 голосов
/ 11 июля 2019

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

    public async Task<IActionResult> MyMethod(Int ID, decimal confirmQty)
            {               
               using (var tran = _context.Database.BeginTransaction())
               {
                try
                {
                   // Need to Lock here whether single record or multiple records
                    var invReduce = _context.Inventorys.Where(w=>w.id == ID).FirstOrDefault();
                    invReduce.availQty -= confirmQty;

                    Thread.Sleep(60000); // One Min
                    await _context.SaveChangesAsync();
                    tran.Commit();
                    // Need to Un-Lock here whether single record or multiple records
                }
                catch (Exception ex)
                {
                    tran.Rollback();
                }
              }
             return Ok();
            }

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

Обновление

Например: для идентификатора: 1, количество равно 1000, запросы первого пользователя уменьшить числона 100 2-й пользователь также отправляет запросы на 100 для уменьшения одновременно и до того, как 1-й пользователь saveChanges () вступает в силу.Окончательное уменьшение кол-во должно быть 1000 - 100 - 100 = 800.

Итак, до завершения операции 1-го пользователя запрос 2-го пользователя должен быть в очереди.

Я использую Asp.Net Core 2.2Code First, PostgreSQL, нет хранимых процедур.

Как мне здесь заблокировать строки?

Ответы [ 5 ]

1 голос
/ 11 июля 2019

Я предлагаю вам использовать следующий необработанный запрос на обновление:

UPDATE MyInv
SET qty = qty - @confirmQty
WHERE ID = @ID AND qty >=  @ConfirmQty

Это предотвращает проблемы параллелизма, с которыми вы сталкиваетесь в вашем коде.

Примечание qty >= @ConfirmQty предотвращает установку количестваниже 0. Вы можете проверить затронутые строки, если это 0, вы можете сказать, что не хватает предметов, чтобы вытащить инвентарь.

0 голосов
/ 11 июля 2019

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

class Inventory
{
      //properties
      public int Version {get; set;}
}

и каждый SaveChanges () будет иметь это свойство

inventory.Version = inventory.Version + 1;

, тогда, если у нас обоих будет Версия = 1, и один из нас обновил одно и то же поле раньше другого, возникнет ошибка из-за увеличения версии.

Пример проверки ниже

var inventory = context.Inventory.FirstOrDefault(x => x.Id == Model.InventoryId);

 //check if inventory is not null if not continue
 if (inventory.Version != Model.Version)
 {
      //throw exception, DbContextConcurrencyIssue, error handling codes
 }
 else
 {
     //continue with process
 }

Любое обновление увеличивает версию и не будет совпадать с другими пользователями, имеющими предыдущую версию

0 голосов
/ 11 июля 2019
public async Task<IActionResult> MyMethod(Int ID, decimal confirmQty)
    {
        using(var tran = _context.Database.BeginTransaction())
        {
            try
            {

                var invReduce= _context.MyInv.Where(w => w.ID == ID).FirstOrDefault();
                inventoryReduce.qty -= confirmQty;
    // some long operation too goes here...
                await _context.SaveChangesAsync();

                tran.Commit();
            }
            catch
            {
                tran.Rollback();
                // log error if necessary
            }

            return Ok();
    }
0 голосов
/ 11 июля 2019

Такие схемы блокировки известны как пессимистичные блокировки и более подвержены проблемам, чем альтернатива оптимистической блокировки.Оптимистичный вообще не является механизмом блокировки;это позволяет любому пользователю, у которого есть та же самая запись, попытаться сделать их редактирование.В рамках обновления ORM передает все предыдущие значения обратно в дБ и формирует запрос таким образом, что сравнивает каждое текущее значение таблицы с каждым предыдущим значением, известным в orm (с момента извлечения записи).Если какие-либо значения были изменены другим пользователем, обновление завершится неудачно и вернет 0 записей обновлений.На этом этапе orm может выдать вам исключение, указывающее, что кто-то еще редактировал ту же запись.Вы используете это исключение и информируете пользователя, возможно, давая ему выбор, что делать:

  • перезаписать свои с моим
  • оставить свои и отказаться от моего
  • объединитьс их

Вы видели это при кодировании и фиксации ваших изменений в управлении исходным кодом, я уверен:)

Конечно, вы должны написать интерфейс для этогоно обычно это правильно, потому что только пользователь может знать, какими должны быть данные.Если вы не предлагаете объединение, тогда это может быть простое диалоговое окно «оставь меня / оставь их»

Ваше предложение хранить вещи в очереди и только последовательно вносить изменения не имеет особого смысла дляменя, потому что второе редактирование - это редактирование данных, которые уже отредактировал первый пользователь;откуда вы знаете, что у вас получится действительное состояние, если вы решите проблему параллелизма программно?Если вы просто хотите переписать изменения person1 в person2, то вам вообще не нужен контроль параллелизма

Я уже говорил о том, как работает оптимистичная система параллелизма, но при условии, что вы используете EF Core,в прекрасном руководстве есть много чего сказать: https://docs.microsoft.com/en-us/ef/core/saving/concurrency

0 голосов
/ 11 июля 2019

Попробуйте использовать в запросах транзакции, которые должны быть атомарными (никакие операции не могут быть выполнены с данными, затронутыми этой операцией).

Читать это например.

Дополнительно читайте о различных уровнях блокировки, чтобы предотвратить одновременное обновление и т. Д.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...