Linq Select не получит более 3 подуровней данных объекта в EF Core - PullRequest
3 голосов
/ 20 мая 2019

Я заменил имена объектов на вымышленные, прежде чем кто-либо подвергнет сомнению странность моего бизнес-кейса для этой базы данных :)

Если я заменю FavouriteBook.Name в приведенном ниже коде на FavouriteBookId.ToString (), я сделаю этополучите это обратно хорошо, так как всегда есть любимая книга, если есть пользователь.Следующий код также работает, если в магазине нет пользователей.Но как только есть пользователи ... Похоже, что они не хотят получать данные, если они идут на несколько уровней глубже, чем Profile.

(Профиль - обязательный объект пользователя, а любимая книга - обязательный объект профиля. «Имя» - это строковое свойство объекта FavouriteBook)

var ret = _context.Shops.Where(x => x.ShopId == shopId);
var selected= ret.Select(y => new UserSummaryRow //my DTO
{
    //…other properties being set have been trimmed
    UserFavouriteBook = 
      y.User.FirstOrDefault(x => x.UserId == y.UserId) == null ? "N/A" 
    : y.User.FirstOrDefault(x => x.UserId == y.UserId).Profile.FavouriteBook.Name

});
var summary = await selected.ToListAsync();
return summary;

Когда строка свыполняется «await», метод API, вызвавший этот метод репозитория, возвращает неверный запрос с ошибкой:

  • $ exception {System.NullReferenceException: ссылка на объект не установлена ​​для экземпляра объектаобъект.в lambda_method (Closure, Object []) в Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.TaskLiftingExpressionVisitor. ExecuteAsync [T] (IReadOnlyList 1 taskFactories, Func 2 селектор) в Microsoft.EntityFync.1.EnumeratorExceptionInterceptor.MoveNext (CancellationToken cancellationToken) в System.Linq.AsyncEnumerable.Aggregate [TSource, TAccumulate, TResult] (аккумулятор IAsyncEnumerable 1 source, TAccumulate seed, Func 3, функции Func 2 resultSelector, CancellationToken cancellationToken) at {namespace of repo method}(Int32 RecId, List 1 в строке в минутах).пространство имен в методе контроллера API} (String dtoString) в C: \ Dev} путь к репо}: строка 608} System.NullReferenceException

Вывод показывает:

Microsoft.EntityFrameworkCore.Query: Ошибка: в базе данных возникла исключительная ситуация при повторении результатов запроса для типа контекста "{пространство имен моего контекста}".System.NullReferenceException: ссылка на объект не установлена ​​на экземпляр объекта.в lambda_method (Closure, Object []) в Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.TaskLiftingExpressionVisitor._ExecuteAsync [T] (селектор IReadOnlyList 1 taskFactories, Func 2) в Microsoft.EntityFrameery26EntityEuityExuIureEuIureEuIureEuEQueryUuEQueryUuEQueryQueryCureTecureUUIUIQueryQueryCuserExuIureExuIureExuIureExuIureExuIureExuIтE.MoveNext (CancellationToken cancellationToken)

Я использую .NET Core / EF core / SQL server 13.0.

Ответы [ 2 ]

2 голосов
/ 20 мая 2019

Я могу точно сказать, в чем проблема, потому что это зависит от используемой версии EF Core - перевод / обработка запросов EF Core все еще нестабильна.Было бы неплохо, если бы вы включили вывод журнала EF Core, например, выполненные запросы SQL, предупреждения оценки клиента, если таковые имеются, и т. Д.

Но в общем случае такие выражения

y.User.FirstOrDefault(x => x.UserId == y.UserId).Profile.FavouriteBook.Name

всегда подозрительны - правильное выполнение зависит исключительно от реализации поставщиком запроса свойств потенциально null «объекта», возвращаемого FirstOrDefault.LINQ to Objects определенно выбросит NRE.EF Core, если использует оценку сервера, должен иметь возможность обрабатывать его, возвращая null, но, согласно исключению, это не связано ни с переводом, ни с оценкой клиентского / смешанного результата.

С учетом сказанного, чтоЯ лично попытался бы использовать эквивалентный «естественный» способ возврата null конечного значения, используя Where + Select, содержащий конечное свойство, и , затем , применяя FirstOrDefault, например,

UserFavouriteBook = y.User
    .Where(x => x.UserId == y.UserId)
    .Select(x => x.Profile.FavouriteBook.Name)
    .FirstOrDefault() ?? "N/A" 
0 голосов
/ 20 мая 2019

Похоже, ваши ссылочные объекты не загружаются по требованию. У вас Lazy loading определен правильно?

Вы можете загрузить эти ссылки напрямую, позвонив

.INCLUDE ()

Так что вам нужно изменить

_context.Shops.Include(s=> s.User.Profile.FavouriteBook)

Тогда вы можете сделать остальную часть фильтрации и проецирования.

...