繁体   English   中英

EF Count()> 0,但First()引发异常

[英]EF Count() > 0 but First() throws exception

我遇到了一个奇怪的问题。 当用户访问我的Web应用程序的任何页面时,我都会检查用户是否有权访问它,并提供首次试用期。

这是我的代码:

List<string> temp_workers_id = new List<string>();
...
if (temp_workers_id.Count > 6)
                {
                    System.Data.SqlTypes.SqlDateTime sqlDate = new System.Data.SqlTypes.SqlDateTime(DateTime.Now.Date);    
var rusers = dbctx.tblMappings.Where(tm => temp_workers_id.Any(c => c == tm.ModelID));
    var permissions = dbctx.UserPermissions
       .Where(p => rusers
          .Any(ap => ap.UserID == p.UserID)
             && p.DateStart != null 
             && p.DateEnd != null 
             && p.DateStart <= sqlDate.Value 
             && p.DateEnd >= sqlDate.Value);

    if (permissions.Count() < 1)
    {
       permissions = dbctx.UserPermissions
          .Where(p => rusers
             .Any(ap => ap.UserID == p.UserID) 
                && p.DateStart == null 
                && p.DateEnd == null);

       var used = dbctx.UserPermissions
          .Where(p => rusers
             .Any(ap => ap.UserID == p.UserID) 
                && p.DateStart != null 
                && p.DateEnd != null);

    if (permissions.Count() > 0 && used.Count() < 1)
    {
       var p = permissions.First();
       using (Models.TTTDbContext tdbctx = new Models.TTTDbContext())
       {
              var tp = tdbctx.UserPermissions.SingleOrDefault(tup => tup.UserID == p.UserID);
              tp.DateStart = DateTime.Now.Date;
              tp.DateEnd = DateTime.Now.Date.AddDays(60);
              tdbctx.SaveChanges();
       }

这里的First()方法抛出异常:

序列不包含任何元素

那怎么可能呢?

编辑:我不认为用户打开两个浏览器并同时在此处导航,但是可能是并发问题吗?

您声称您仅在服务器日志中找到了它,而在调试过程中没有遇到它。 这意味着在这些行之间:

if (permissions.Count() > 0)
{
    var p = permissions.First();

其他一些进程或线程更改了您的数据库,以使查询不再与任何文档匹配。

这是由持有惰性评估资源的permissions引起的,这意味着仅在迭代查询时才执行查询( Count()First() )这样做)。

因此,在Count() ,执行查询:

SELECT COUNT(*) ... WHERE ...

此时,该行返回一行。 然后在外部修改数据,从而导致下一个查询(在First() ):

SELECT n1, n2, ... WHERE ...

返回零行,导致First()抛出。

现在,如何解决该问题,取决于您,并且完全取决于您要如何对这种情况进行建模。 这意味着第二个查询实际上是正确的:在一刻,没有到的符合查询条件的更多的行。 您可以实现一次查询:

permissions = query.Where(...).ToList()

但这意味着您的逻辑将对过时的数据进行操作。 如果您使用FirstOrDefault()也会发生同样的情况:

var permissionToApply = permissions.FirstOrDefault();
if (permissionToApply != null)
{
    // rest of your logic
}

因此,这基本上是一个输球的情况。 您总是有可能使用过时的数据,这意味着下一个代码:

 tdbctx.UserPermissions.SingleOrDefault(tup => tup.UserID == p.UserID);

也会扔。 因此,每次查询数据库时,都必须以一种可以处理不再存在的记录的方式编写代码。

暂无
暂无

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

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