Ссылка на объект лямбда-выражения EF Core не установлена ​​для экземпляра объекта в нескольких соединениях - PullRequest
1 голос
/ 24 апреля 2020

У меня странная ошибка NullReferenceException при запросе данных с использованием лямбда-синтаксиса ядра Entity Framework.

с использованием этого кода

           var usersWithRights = await _dbContext.TblUsers.Where(x => x.IsInternal).Select(x => new
            {
                RightIds = x.TblInternalUserRoles.FirstOrDefault().Role.TblInternalRoleRights.Select(i => i.RightId).ToList()
            }).ToListAsync();

Где работает тот же код при применении Count вместо Select, как

           var usersWithRights = await _dbContext.TblUsers.Where(x => x.IsInternal).Select(x => new
            {
                RightIds = x.TblInternalUserRoles.FirstOrDefault().Role.TblInternalRoleRights.Count
            }).ToListAsync();

Над кодом, используя Count, дайте мне точный результат подсчета, но я хочу выбрать RightIds. Я перекрестно проверил, существует ли запись в моей базе данных, и в результате, когда я запрашиваю, используя Count, он дает мне точный результат.

Я просто хочу спросить, есть ли какие-либо ограничения для ядра платформы Entity, пока присоединение данных? например, в EF Core разрешено максимальное количество объединений или я могу объединить любое количество таблиц?

1 Ответ

1 голос
/ 27 апреля 2020

Ограничений на присоединение нет, но, к сожалению, все еще есть много недостатков / ошибок / проблем в переводе запросов EF Core некоторых конструкций LINQ.

Обычно вам не нужно Include / ThenInclude в проекционные (Select) запросы, потому что они игнорируются. Но получение NRE без них здесь указывает на попытку оценки клиента (EF Core 3.x все еще поддерживает оценку клиента для некоторых конструкций, и в основном в окончательной проекции, как здесь), что, в свою очередь, означает неудачный перевод.

Здесь Кажется, проблема в

x.TblInternalUserRoles.FirstOrDefault().Role.TblInternalRoleRights.Select(i => i.RightId)

, т. е. преобразовании последовательности (x.TblInternalUserRoles) в один элемент (.FirstOrDefault()) и последующем получении подпоследовательности (.Role.TblInternalRoleRights).

Рабочим решением является используйте оператор SelectMany для выравнивания исходной последовательности. FirstOrDefault() должен быть удален (для меня это не имеет смысла) или, если действительно необходимо, заменен соответствующим оператором эквивалентной последовательности Take(1).

например

RightIds = x.TblInternalUserRoles
    .SelectMany(ur => ur.Role.TblInternalRoleRights.Select(i => i.RightId))
    .ToList()

или

RightIds = x.TblInternalUserRoles
    .SelectMany(ur => ur.Role.TblInternalRoleRights, (ur, i) => i.RightId)
    .ToList()

или

RightIds = x.TblInternalUserRoles
    .SelectMany(ur => ur.Role.TblInternalRoleRights)
    .Select(i => i.RightId)
    .ToList()
...