EF: оператор «Включить» и «Где» в одной и той же ссылочной сущности не выполняется - PullRequest
0 голосов
/ 30 октября 2019

У меня есть следующий запрос EF, который отлично работает. Обратите внимание, что я только что обнаружил, что могу напрямую фильтровать ссылочное свойство навигации.

context.AlertDetailsDbSet

                        .Where(ad => ad.Alert.CompanyId == companyId && ad.TrackedVehicule.RowEnabled == true)

                         // A limit is applied on returned elements
                         .Take(1000)

                         .OrderByDescending(ad => ad.AlertDateTime)

Я хотел бы включить свойство навигационной ссылки TrackedVehicule. Поэтому я наивно добавил предложение .Include:

context.AlertDetailsDbSet

                        .Include(ad => ad.TrackedVehicule)

                        .Where(ad => ad.Alert.CompanyId == companyId && ad.TrackedVehicule.RowEnabled == true)

                         // A limit is applied on returned elements
                         .Take(1000)

                         .OrderByDescending(ad => ad.AlertDateTime)

Но на этот раз запрос не удался с этим странным System.Data.SqlTypes.SqlNullValueException

   at System.Data.SqlClient.SqlBuffer.get_Int64()
   at System.Data.SqlClient.SqlDataReader.GetInt64(Int32 i)
   at Microsoft.EntityFrameworkCore.Storage.Internal.TypedRelationalValueBufferFactory.Create(DbDataReader dataReader)
   at Microsoft.EntityFrameworkCore.Query.Internal.AsyncQueryingEnumerable`1.AsyncEnumerator.<BufferlessMoveNext>d__12.MoveNext()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.<ExecuteAsync>d__7`2.MoveNext()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.EntityFrameworkCore.Query.Internal.AsyncQueryingEnumerable`1.AsyncEnumerator.<MoveNext>d__11.MoveNext()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Linq.Internal.Lookup`2.<CreateForJoinAsync>d__16.MoveNext() in D:\a\1\s\Ix.NET\Source\System.Interactive.Async\Lookup.cs:line 298
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Linq.AsyncEnumerable.GroupJoinAsyncEnumerable`4.GroupJoinAsyncEnumerator.<MoveNext>d__8.MoveNext() in D:\a\1\s\Ix.NET\Source\System.Interactive.Async\GroupJoin.cs:line 153
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Linq.AsyncEnumerable.SelectManyAsyncIterator`3.<MoveNextCore>d__12.MoveNext() in D:\a\1\s\Ix.NET\Source\System.Interactive.Async\SelectMany.cs:line 252
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Linq.AsyncEnumerable.AsyncIterator`1.<MoveNext>d__10.MoveNext() in D:\a\1\s\Ix.NET\Source\System.Interactive.Async\AsyncIterator.cs:line 112
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Linq.AsyncEnumerable.SelectEnumerableAsyncIterator`2.<MoveNextCore>d__7.MoveNext() in D:\a\1\s\Ix.NET\Source\System.Interactive.Async\Select.cs:line 106
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Linq.AsyncEnumerable.AsyncIterator`1.<MoveNext>d__10.MoveNext() in D:\a\1\s\Ix.NET\Source\System.Interactive.Async\AsyncIterator.cs:line 109
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider.ExceptionInterceptor`1.EnumeratorExceptionInterceptor.<MoveNext>d__5.MoveNext()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Linq.AsyncEnumerable.<Aggregate_>d__6`3.MoveNext() in D:\a\1\s\Ix.NET\Source\System.Interactive.Async\Aggregate.cs:line 120
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at RTE.Technologies.SafeProtect.Common.Data.DataBridge.Core.AlertDetailDataBridge.<GetAlertDetailAsync>d__2.MoveNext() in C:\Users\olivier.matrot\source\repos\SafeProtect\SafeProtect.Common\SafeProtect.Common.Data\DataBridge\Core\AlertDetailDataBridge.cs:line 86

Любая помощь приветствуется.

РЕДАКТИРОВАТЬ 1 : первый работающий запрос генерирует следующий SQL:

exec sp_executesql N'SELECT [t].[AlertDetailID], [t].[AckMachineName], [t].[AckPhoneNumber], [t].[AckTime], [t].[AckUserName], [t].[AlertDateTime], [t].[AlertID], [t].[AlertedCorridorId], [t].[AlertedItemId], [t].[AssociatedVehiculeID], [t].[AssociatedVehiculeUserID], [t].[Context], [t].[CustomID], [t].[CustomInfo], [t].[DbInsertTime], [t].[IsFleetAlert], [t].[MessageStatus], [t].[ReceivedTime], [t].[RowVersion], [t].[SafeProtectCustomInfo], [t].[TrackedVehiculeID], [t].[TrackedVehiculeUserID]
FROM (
    SELECT TOP(@__p_1) [ad].[AlertDetailID], [ad].[AckMachineName], [ad].[AckPhoneNumber], [ad].[AckTime], [ad].[AckUserName], [ad].[AlertDateTime], [ad].[AlertID], [ad].[AlertedCorridorId], [ad].[AlertedItemId], [ad].[AssociatedVehiculeID], [ad].[AssociatedVehiculeUserID], [ad].[Context], [ad].[CustomID], [ad].[CustomInfo], [ad].[DbInsertTime], [ad].[IsFleetAlert], [ad].[MessageStatus], [ad].[ReceivedTime], [ad].[RowVersion], [ad].[SafeProtectCustomInfo], [ad].[TrackedVehiculeID], [ad].[TrackedVehiculeUserID]
    FROM [AlertDetail] AS [ad]
    LEFT JOIN [Vehicule] AS [ad.TrackedVehicule] ON [ad].[TrackedVehiculeID] = [ad.TrackedVehicule].[VehiculeID]
    INNER JOIN [Alert] AS [ad.Alert] ON [ad].[AlertID] = [ad.Alert].[AlertID]
    WHERE ([ad.Alert].[CompanyID] = @__companyId_0) AND ([ad.TrackedVehicule].[RowEnabled] = 1)
) AS [t]
ORDER BY [t].[AlertDateTime] DESC',N'@__p_1 int,@__companyId_0 int',@__p_1=1000,@__companyId_0=1

РЕДАКТИРОВАТЬ 2 : результат добавлениявызов Включить включает следующий второй запрос:

SELECT [ad.TrackedVehicule0].[VehiculeID], [ad.TrackedVehicule0].[Address], [ad.TrackedVehicule0].[AddressProtocol], [ad.TrackedVehicule0].[BoardID], [ad.TrackedVehicule0].[Category], [ad.TrackedVehicule0].[CompanyID], [ad.TrackedVehicule0].[CustomId], [ad.TrackedVehicule0].[DbInsertTime], [ad.TrackedVehicule0].[Description], [ad.TrackedVehicule0].[GpsBoxTrackingDelay], [ad.TrackedVehicule0].[GpsBoxType], [ad.TrackedVehicule0].[HardwareID], [ad.TrackedVehicule0].[HasGeoWorker], [ad.TrackedVehicule0].[IconID], [ad.TrackedVehicule0].[Name], [ad.TrackedVehicule0].[PhoneNumber], [ad.TrackedVehicule0].[RowEnabled], [ad.TrackedVehicule0].[RowVersion], [ad.TrackedVehicule0].[VehiculeUserID]
FROM [Vehicule] AS [ad.TrackedVehicule0]

Обработка этого дополнительного результирующего набора, кажется, беспокоит EF. Кроме того, этот выбор извлекает весь контент из таблицы, что может привести к ужасной производительности.

Ответы [ 2 ]

0 голосов
/ 31 октября 2019

Я опубликовал эту проблему на GitHub, и они попросили меня попробовать EF.Core 3.1 Preview .

Я могу подтвердить, что теперь она работает нормально.

Для информации, hre является сгенерированным запросом:

exec sp_executesql N'SELECT [t].[AlertDetailID], [t].[AckMachineName], [t].[AckPhoneNumber], [t].[AckTime], [t].[AckUserName], [t].[AlertDateTime], [t].[AlertID], [t].[AlertedCorridorId], [t].[AlertedItemId], [t].[AssociatedVehiculeID], [t].[AssociatedVehiculeUserID], [t].[Context], [t].[CustomID], [t].[CustomInfo], [t].[DbInsertTime], [t].[IsFleetAlert], [t].[MessageStatus], [t].[ReceivedTime], [t].[RowVersion], [t].[SafeProtectCustomInfo], [t].[TrackedVehiculeID], [t].[TrackedVehiculeUserID], [v0].[VehiculeID], [v0].[Address], [v0].[AddressProtocol], [v0].[BoardID], [v0].[Category], [v0].[CompanyID], [v0].[CustomId], [v0].[DbInsertTime], [v0].[Description], [v0].[GpsBoxTrackingDelay], [v0].[GpsBoxType], [v0].[HardwareID], [v0].[HasGeoWorker], [v0].[IconID], [v0].[Name], [v0].[PhoneNumber], [v0].[RowEnabled], [v0].[RowVersion], [v0].[VehiculeUserID]
FROM (
    SELECT TOP(@__p_1) [a].[AlertDetailID], [a].[AckMachineName], [a].[AckPhoneNumber], [a].[AckTime], [a].[AckUserName], [a].[AlertDateTime], [a].[AlertID], [a].[AlertedCorridorId], [a].[AlertedItemId], [a].[AssociatedVehiculeID], [a].[AssociatedVehiculeUserID], [a].[Context], [a].[CustomID], [a].[CustomInfo], [a].[DbInsertTime], [a].[IsFleetAlert], [a].[MessageStatus], [a].[ReceivedTime], [a].[RowVersion], [a].[SafeProtectCustomInfo], [a].[TrackedVehiculeID], [a].[TrackedVehiculeUserID], [a0].[AlertID] AS [AlertID0]
    FROM [AlertDetail] AS [a]
    INNER JOIN [Alert] AS [a0] ON [a].[AlertID] = [a0].[AlertID]
    LEFT JOIN [Vehicule] AS [v] ON [a].[TrackedVehiculeID] = [v].[VehiculeID]
    WHERE ((((([a0].[CompanyID] = @__companyId_0) AND @__companyId_0 IS NOT NULL) AND [v].[VehiculeID] IS NOT NULL) AND (([v].[RowEnabled] = CAST(1 AS bit)) AND [v].[RowEnabled] IS NOT NULL)) AND ((([v].[CompanyID] = @__companyId_0) AND ([v].[CompanyID] IS NOT NULL AND @__companyId_0 IS NOT NULL)) OR ([v].[CompanyID] IS NULL AND @__companyId_0 IS NULL))) AND (([v].[GpsBoxType] = 29) AND [v].[GpsBoxType] IS NOT NULL)
) AS [t]
LEFT JOIN [Vehicule] AS [v0] ON [t].[TrackedVehiculeID] = [v0].[VehiculeID]
ORDER BY [t].[AlertDateTime] DESC',N'@__p_1 int,@__companyId_0 int',@__p_1=1000,@__companyId_0=1
0 голосов
/ 30 октября 2019

Проблема в том, что вы создали объединение, которое означает, что любые результаты с TrackedVehicule, установленным на null, приведут к исключению: ad.TrackedVehicule.RowEnabled == true), потому что вы не можете посмотреть на RowEnabled на null object.

Я не знаю точно, почему первый запрос работает, но если вы запустите sqlprofiler для просмотра sql, который генерирует EF, я уверен, что вы узнаете.

Исправление будет зависеть от того, чего вы хотите достичь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...