2015-05-12 6 views
11

Una query per una griglia in un'applicazione Web .NET supportata da Entity Framework su cui sto lavorando stava dando un errore 500 (The cast to value type 'System.Int32' failed because the materialized value is null. Either the result type's generic parameter or the query must use a nullable type.) quando l'oggetto della riga della griglia aveva zero elementi figlio in una particolare relazione uno-a-molti . Il null stava tornando su una proprietà intera non correlata. Sconcertante, invertire l'ordine delle due istruzioni Let indipendenti nell'espressione Linq ha fatto scomparire l'errore.Perché l'ordine delle istruzioni LET è importante in questa query di Entity Framework?

Cioè, se v'è un solo Widget (ID: 1, createdOn: alcuni datetime), che non ha Bar e una 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 } 

o

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} come previsto, ma

from w in Widgets.OrderBy(w => w.CreatedOn) 
let bar = w.Bars.FirstOrDefault() 
let foo = w.Foos.FirstOrDefault() 
select new { w.WidgetID, foo.fValue } 

torna con {WidgetID: 1, fValue: NULL} che naturalmente si blocca perché Foo.fValue è un numero intero.

Tutte e tre le espressioni generano leggermente diverse query SQL sotto Entity Framework, che mi aspetterei - l'espressione non riuscendo contiene la clausola

... 
(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] 
... 

che credo sia il colpevole (0 Bar incrociati con 1 foo = 0 risultati). Quindi capisco il "come" dell'errore; quello che mi dà è che non ho idea perché l'ordine dei LETs o se ordino con una chiamata al metodo Linq vs un'espressione Linq dovrebbe fare la differenza.

Ecco lo schema della tabella ridotta/dati se si vuole sperimentare da soli:

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 
) 

Può spiegare perché quelle 3 espressioni non sono logicamente equivalenti in Entity Framework?

+1

Penso che tu abbia appena trovato un bug in EF. – Wasp

risposta

1

Credo che questo sia un bug relativo a questo problema Entity Framework noto: https://entityframework.codeplex.com/workitem/1196. In base al problema, quando si utilizza order by, let e FirstOrDefault, l'albero delle query viene compilato in una query SQL con errori.

Purtroppo il problema ha quasi due anni, quindi questo particolare bug potrebbe non essere una priorità per il team EF. Forse verrà risolto in EF7!

+0

Beh, questo è sfortunato. –

Problemi correlati