Как предотвратить вторую операцию над контекстом в этом случае? - PullRequest
0 голосов
/ 29 октября 2018

У меня есть такой код:

Он должен загружать данные из БД с помощью «пользовательского» предиката в Where

, который должен спросить БД о разрешениях, чтобы определить true / false

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 голосов
/ 29 октября 2018

Корень проблемы в том, что вы можете использовать объект DbContext только для одного запроса за раз. Но CanPerformAction выполняет свой собственный вызов БД (из-за FirstOrDefault) в то время, как getUsersWhoCanDoSomething. Вот почему вы получаете исключение.

Ваш ответ будет работать, но вы запрашиваете больше данных, чем хотите, а затем отбрасываете некоторые. Если у вас более 10 000 пользователей, то из-за этого вы можете пропустить некоторых пользователей (из-за Take(10000)).

Это должно сделать то же самое (я думаю - я не знаю вашу точную схему БД). Он объединяет условие в запросе, поэтому вы получаете только те данные, которые вам нужны.

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

Другой способ сделать то же самое - это по-прежнему использовать ваш отдельный метод (в любом случае все, что после => является технически отдельным методом), но не ссылаться на _context или FirstOrDefault (который вызывает отдельный БД вызов). Это сделало бы то же самое, что и мой код выше, если вы используете .Where(x => CanPerformAction(user)).

private bool CanPerformAction(User user)
{
    return user.Permissions.Any(l => l.Level > 5);
}
0 голосов
/ 29 октября 2018

Решение:

Перемещение 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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...