Учитывая, что это относительно небольшое количество возможных идентификаторов, я бы вместо этого посмотрел на удержание таблицы назначения идентификаторов, состоящей из:
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)
между кодом аренды и театральной группой. Такой подход сделает повторную переработку кодов аренды намного чище, но расширит окно для нескольких процессов, чтобы попытаться зарезервировать один и тот же код аренды.