Как создать параллельный Sequence Gen в EF Core + PGSQL - PullRequest
0 голосов
/ 29 апреля 2020

У меня есть. net Core 2 API + Entity Framework + PostgreSQL. Таблица с целочисленным полем, скажем,

class Order
{
    public Guid Id { get; set;}
    public int ShopId { get; set; }
    public OrderType Type { get; set; } 
    public int OrderId { get; set; }
}

В этой таблице у нас есть заказы из многих магазинов, два типа заказов: OldSystem и NewSystem. Это означает, что у нас уже есть много старых заказов. Этот новый проект может создавать новые заказы («Новая система»), и нам нужно автоматическое увеличение для OrderId в каждом магазине! Orderd 1, 2, 3, ... в магазине 1, заказы 1, 2, 3 ... в магазине 2.

Другими словами, я мог бы написать что-то вроде:

var lastOrderId = await dbContext.Orders.Where(x =>
        x.ShopId == currentShopId &&
        x.OrderId != null &&
        x.Type == OrderType.NewSystem)
    .MaxAsync(x => x.OrderId);

var nextOrderId = (lastOrderId ?? 0) + 1;

newOrder.OrderId = nextOrderId;
await dbContext.Orders.InsertAsync(newOrder);
await dbContext.SaveChangesAsync();

Но он не защищен от дубликатов. В то же время другой API-запрос может сделать то же самое: получить Max + 1 и Insert + Save.

Я вижу несколько возможных решений, прошу совета.

  1. Optimisti c блокировка: после сохранения проверять дубликаты OrderId (в том магазине и типе), если найдены - генерировать снова, проверять снова и так далее ... В случае высокой загрузки - возможен бесконечный l oop.
  2. Добавьте новую таблицу «Генератор последовательностей», у каждого магазина есть собственная запись, запись блокировки во время генерации - но EF не предоставляет никакого механизма блокировки.
  3. Записывает некоторые необработанные SQL (или хранимая процедура). Звучит не очень хорошо.
  4. Используйте RedLock или что-то еще для какой-то распределенной блокировки (система масштабируема) в коде. Используйте shopId в качестве ключа для блокировки (разрешите разным магазинам генерировать собственные последовательности одновременно). Слишком сложно, и нам нужен Redis для этого решения.

Есть идеи? Заранее спасибо!

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