Запрос для сетки в поддерживаемом Entity Framework.NET-приложении .NET, над которым я работаю, давал ошибку 500 (The cast to value type 'System.Int32' failed because the materialized value is null. Either the result type generic parameter or the query must use a nullable type.
), когда у объекта строки сетки имелись нулевые дочерние элементы в определенном - много отношений. Нуль возвращался к несвязаному целочисленному свойству. Непосредственно, обращая порядок двух независимых операторов Let в выражении Linq, ошибка исчезла.
То есть, если есть только один виджет (ID: 1, CreatedOn: некоторое datetime), у которого нет баров и один Foo (fValue: 96)
from w in Widgets.OrderBy(w => w.CreatedOn)
let foo = w.Foos.FirstOrDefault()
let bar = w.Bars.FirstOrDefault()
select new { w.WidgetID, foo.fValue }
или
from w in Widgets
let bar = w.Bars.FirstOrDefault()
let foo = w.Foos.FirstOrDefault()
orderby w.CreatedOn
select new { w.WidgetID, foo.fValue }
дает {WidgetID: 1, fValue: 96}
, как ожидалось, но
from w in Widgets.OrderBy(w => w.CreatedOn)
let bar = w.Bars.FirstOrDefault()
let foo = w.Foos.FirstOrDefault()
select new { w.WidgetID, foo.fValue }
возвращается с {WidgetID: 1, fValue: NULL}
, который, конечно, сбой, потому что Foo.fValue является целым числом.
Все три выражения генерируют несколько разные SQL-запросы в Entity Framework, которые я ожидал бы - выражение с ошибкой содержит предложение
...
(SELECT TOP (1)
[Extent7].[fValue] AS [fValue]
FROM (SELECT TOP (1) [Extent6].[BarID] AS [BarID]
FROM [dbo].[Bars] AS [Extent6]
WHERE [Extent1].[WidgetID] = [Extent6].[bWidgetID] ) AS [Limit5]
CROSS JOIN [dbo].[Foos] AS [Extent7]
WHERE [Extent1].[WidgetID] = [Extent7].[fWidgetID]) AS [C1]
...
который, я считаю, является виновником (0 баров пересекаются с результатами 1 Foo = 0). Поэтому я понимаю "как" ошибки; то, что меня заводит, заключается в том, что я понятия не имею, почему порядок LET или я OrderBy с вызовом метода Linq против выражения Linq должен иметь значение.
Здесь приведенная схема/данные таблицы, если вы хотите поэкспериментировать:
create table Widgets (
WidgetID int not null primary key,
CreatedOn datetime not null
)
insert Widgets values (1, '1995-02-03')
create table Foos (
FooID int not null primary key,
fWidgetID int not null references Widgets (WidgetID),
fValue int not null
)
insert Foos values (7, 1, 96)
create table Bars (
BarID int not null primary key,
bWidgetID int not null references Widgets (WidgetID),
bValue int not null
)
Можете ли вы объяснить, почему эти 3 выражения не логически эквивалентны в Entity Framework?