繁体   English   中英

如何使用实体框架生成随机数并检查它是否已存在于数据库中

[英]How to generate random number and check if it already exists in database using Entity Framework

我正在开发一个项目,在该项目中我正在帮助使用 ASP.NET MVC Web 应用程序和实体框架为剧院组构建网站。 他们希望能够将他们的空间出租给其他团体,并为此在网站上创建了一个表格供人们提交申请。 我的任务是创建一个租赁代码属性,该属性生成一个随机的 5 位代码并将该值分配给该属性。 我已经能够获得要生成的数字并将其分配给租赁代码属性。

在这一点上,我正在尝试这样做,以便在生成数字时程序运行循环并检查数据库以确保该数字不存在。 如果它确实存在,我希望它生成一个新数字,然后检查它,并继续这样做,直到它有一个唯一的数字。 然后将该编号分配给租赁代码属性。

这是我到目前为止的代码:

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");
}

请让我知道是否需要我提供任何其他数据来解决这个问题。 任何可以让我朝着正确方向前进的东西都非常感谢!

鉴于可能的 ID 数量相对较少,我会考虑持有一个 ID 分配表,其中包括:

RentalCode:Int [PK](标识:开始 10000,增量:1)

序列:GUID(默认值:NewId() 唯一索引)

IsAssigned:位(默认值:false)

创建该表后,插入 89999 行,这将为您提供 10000 - 99999。使用 Default 和 Identity 列,您只需要插入即可创建行而无需提供任何字段。

为此表创建一个实体。

当您想为新剧组分配租借代码时:

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();
}

NewId() GUID 为您提供了一个合理的随机顺序,您可以根据该顺序对租赁代码进行重复排序。 排序然后取第一个未分配的行将为您提供一个快速的随机代码,而无需生成、检查和重试,因为使用分配的租赁代码的数量会导致更多的冲突。

这里的关键是让代码预先保留一个租赁代码,并尽快保存更新的分配标记代码。 这将有助于防止 2 个或更多请求尝试为新组使用相同的租用代码。

你的 TheatreGroup 上的 RentalCode 应该有一个唯一的约束,所以这个代码或调用代码应该在(非常)罕见的并发情况下从 EF 捕获一个DbUpdateException ,其中两个剧院组大致同时创建并且第二个尝试插入使用相同的租赁代码。 上面的代码将采取措施减少这种可能性,但不会阻止它。 这里的异常应该简单地重试操作。

如果您删除剧院组,您可以通过将其分配标志设置回 False 来释放租借代码。 (或者不要,如果您不想重复使用代码。)

或者,可以将 RentalCode 视为从 TheatreGroup 到 RentalCode 表/实体的 FK,您可以避免使用 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) 这种方法将使回收租赁代码更清晰,但会扩大多个进程尝试保留相同租赁代码的窗口。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM