Combattere con EF6 / linq su SQL per ottenere il risultato desiderato. Preferirei non dover creare una vista nel database.
Qualche idea sul perché EF lo sta convertendo in questo modo o su come ingannarlo altrimenti?
Il mio predicato linq:
.Where(x =>
(x.AccountId == viewModel.AccountId || x.AccountId == null)
&& (x.CompanyId == viewModel.CompanyId || x.Company == null)
&& (x.FacilityId == viewModel.FacilityId || x.FacilityId == null)
)
L'SQL generato:
WHERE
(([Extent1].[AccountId] = 1)
OR (([Extent1].[AccountId] IS NULL) AND (1 IS NULL))
OR ([Extent1].[AccountId] IS NULL)
)
AND
(
([Extent1].[CompanyId] = 11)
OR (([Extent1].[CompanyId] IS NULL) AND (11 IS NULL))
OR ([Extent2].[Id] IS NULL)
)
AND
(
([Extent1].[FacilityId] = 1)
OR (([Extent1].[FacilityId] IS NULL) AND (1 IS NULL))
OR ([Extent1].[FacilityId] IS NULL)
)
AND
(
([Extent1].[FacilityId] = 1)
OR (([Extent1].[FacilityId] IS NULL) AND (1 IS NULL))
)
L'SQL che ho pensato di ottenere e ottiene il risultato desiderato:
WHERE
(
([Extent1].[AccountId] = 1)
OR ([Extent1].[AccountId] IS NULL)
)
AND
(
([Extent1].[CompanyId] = 11)
OR ([Extent2].[Id] IS NULL)
)
AND
(
([Extent1].[FacilityId] = 1)
OR ([Extent1].[FacilityId] IS NULL)
)
Per favore prova:
.Where(x =>
(x.AccountId == (int)viewModel.AccountId || x.AccountId == null)
&& (x.CompanyId == (int)viewModel.CompanyId || x.Company == null)
&& (x.FacilityId == (int)viewModel.FacilityId || x.FacilityId == null)
)
O:
var accountId = viewModel.AccountId.GetValueOrDefault();
var companyId = viewModel.CompanyId.GetValueOrDefault();
var facilityId = viewModel.FacilityId.GetValueOrDefault();
...
...
.Where(x =>
(x.AccountId == accountId || x.AccountId == null)
&& (x.CompanyId == companyId || x.Company == null)
&& (x.FacilityId == facilityId || x.FacilityId == null)
)
La query originale faceva riferimento a tipi nullable come parametri, pertanto, EF era necessario per generare un predicato che fosse in grado di funzionare in modo prevedibile quando il valore del parametro è nullo, per questo verrà visualizzato l'extra ([Extent1].[AccountId] IS NULL) AND (@p__linq__0 IS NULL)
. Inserendo i tuoi parametri nel tipo sottolineato nella tua query (in questo caso System.Int32
), EF non vedrà la necessità di farlo perché "pensa" che il tuo parametro non possa essere nullo.
Tutto ciò è necessario perché per impostazione predefinita la connessione al server SQL avrà l'opzione ANSI_NULLS
attiva, questo significa che qualsiasi confronto con NULL
sarà falso, ed è per questo che EF ha bisogno di generare questa logica aggiuntiva (operatore IS NULL
), per assicurarti può ottenere risultati prevedibili quando il valore del parametro è nullo.
Puoi provare questo per vedere gli effetti di ANSI_NULLS
in azione:
SET ANSI_NULLS ON;
SELECT 1 WHERE NULL = NULL;
SET ANSI_NULLS OFF;
SELECT 1 WHERE NULL = NULL;