在这种情况下,如何防止在上下文中进行第二次操作?

时间:2018-10-29 12:37:50

标签: c# asp.net-core entity-framework-core

我有这样的代码:

它必须使用Where

中的“ custom”谓词从db加载数据

必须向db询问有关确定真/假的权限

public List<User> getUsersWhoCanDoSomething()
{
    return _context
            .Users
            .Where(x => CanPerformAction(user))
            .Take(10000)
            .OrderByDescending(x => x.CreationDate)
            .ToList();
}

private bool CanPerformAction(User user)
{
    var permission = _context
    .Permissions
    .FirstOrDefault(x => x.Name == user.Permissions.Name)
    .Level;

    return permission > 5;
}   

如何更改此代码以防止出现此异常:

A second operation started on this context before a previous operation completed.

2 个答案:

答案 0 :(得分:1)

解决方案:

Where / Filter从LINQ链中移出

public List<User> getUsersWhoCan...()
{
    var users = _context
            .Users
            .Include(x => x.Permissions)
            .Take(10000)
            .OrderByDescending(x => x.CreationDate)
            .ToList();

    var tempList = new List<User>();

    foreach (var user in users)
    {
        if (CanPerformAction(user))
        {
            tempList.Add(user);
        }
    }

    return tempList;
}

答案 1 :(得分:0)

问题的根源在于,一次只能对一个查询使用DbContext对象。但是CanPerformActionFirstOrDefault执行期间正在执行自己的数据库调用(由于getUsersWhoCanDoSomething)。这就是为什么您要获得例外。

您的答案将起作用,但是您要获取的数据超出了您的期望,然后丢弃了一些数据。如果您的用户数超过10,000,则可能会因此而丢失一些用户(由于Take(10000))。

这应该做相同的事情(我想-我不知道您的确切数据库架构)。它将条件组合到查询中,因此您仅获得所需的数据。

return _context
        .Users
        .Where(u => u.Permissions.Any(l => l.Level > 5))
        .Take(10000)
        .OrderByDescending(x => x.CreationDate)
        .ToList();

做同样事情的另一种方法是仍然使用单独的方法(从技术上来说,=>之后的任何东西都是单独的方法),但是不要引用_contextFirstOrDefault (这会触发一个单独的数据库调用)。如果您使用.Where(x => CanPerformAction(user)),这将与我上面的代码完全相同。

private bool CanPerformAction(User user)
{
    return user.Permissions.Any(l => l.Level > 5);
}