Как сгенерировать случайное число и проверить, существует ли оно уже в базе данных, используя Entity Framework - PullRequest
0 голосов
/ 29 января 2020

Я работаю над проектом, в котором помогаю создать веб-сайт для театральной группы, используя ASP. NET MVC веб-приложение и Entity Framework. Они хотят иметь возможность сдавать свои помещения в аренду другим группам, и для этого на веб-сайте была создана форма, позволяющая людям подавать заявки. Мне было поручено создать атрибут кода аренды, который генерирует случайный код 5 di git и присваивает это значение атрибуту. Мне удалось получить номер для генерации и присвоить его атрибуту кода аренды.

На данный момент я пытаюсь сделать так, чтобы при создании номера программа запускала al oop и проверяла базы данных, чтобы убедиться, что номер еще не существует. И если он существует, я хочу, чтобы он сгенерировал новый номер, затем проверьте это и продолжайте делать это, пока у него не будет уникального номера. Затем присвойте этот номер атрибуту кода аренды.

Вот код, который у меня есть:

if (ModelState.IsValid)
{
    db.RentalRequests.Add(rentalRequest);
    var randomNum = new Random();
    int codeNum = randomNum.Next(10000, 99999);
    rentalRequest.RentalCode = codeNum;

    db.SaveChanges();

    return RedirectToAction("Index");
}

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

1 Ответ

0 голосов
/ 29 января 2020

Учитывая, что это относительно небольшое количество возможных идентификаторов, я бы вместо этого посмотрел на удержание таблицы назначения идентификаторов, состоящей из:

RentalCode: Int [PK] (Удостоверение: начало 10000, приращение: 1)

Последовательность: GUID (по умолчанию: NewId () Уникальный индекс)

IsAssigned: Бит (По умолчанию: false)

После создания этой таблицы вставьте 89999 строк, которые дадут вам 10000 - 99999. Для столбцов «По умолчанию» и «Удостоверение» вам просто нужна вставка, чтобы создать строку без каких-либо полей.

Создать объект для этой таблицы.

Когда вы хотите назначить аренду код новой театральной группы:

using(var context = new AppContext())
{
    var rentalCode = context.RentalCodes.Where(x => !x.IsAssigned)
        .OrderBy(x => x.Sequence)
        .FirstOrDefault();
    if(rentalCode == null)
        throw new InvalidOperationException("All rental codes are assigned.");

    rentalCode.IsAssigned = true;
    context.SaveChanges();  // Fetch our next free code, mark it as assigned, and save changes quickly to minimize concurrency risk.

    var theatreGroup = new TheatreGroup
    {
        // fill in details...
        RentalCode = rentalCode.RentalCode;
    }
    context.TheatreGroups.Add(theatreGroup);
    context.SaveChanges();
}

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

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

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

Если вы удалите TheatreGroup, вы можете освободить код аренды, установив присвоенный ему флаг обратно в False. (Или нет, если вы не хотите, чтобы коды использовались повторно.)

В качестве альтернативы RentalCode может рассматриваться как FK от TheatreGroup до RentalCode таблицы / сущности, и вы можете избежать флага IsAssigned и просто полагаясь на ассоциацию, чтобы найти следующий неназначенный:

using (var context = new AppDbContext())
{
    var rentalCode = context.RentalCodes
        .Where(x => x.TheatreGroup == null)
        .OrderBy(x => x.Sequence)
        .FirstOrDefault();

    // ...
}

Это будет полагаться на HasOptional(x => x.TheatreGroup).WithRequired(x => x.RentalCode) между кодом аренды и театральной группой. Такой подход сделает повторную переработку кодов аренды намного чище, но расширит окно для нескольких процессов, чтобы попытаться зарезервировать один и тот же код аренды.

...