Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Introduction
Az SQL-adatbázisok 3 értékű logikán (true, false, null) működnek összehasonlítások végrehajtásakor, szemben a C# logikai logikával. A LINQ-lekérdezések SQL-re történő fordításakor az EF Core megpróbálja kompenzálni a különbséget a lekérdezés egyes elemeinek további null értékű ellenőrzéseinek bevezetésével.
Ennek szemléltetéséhez definiáljuk a következő entitást:
public class NullSemanticsEntity
{
public int Id { get; set; }
public int Int { get; set; }
public int? NullableInt { get; set; }
public string String1 { get; set; }
public string String2 { get; set; }
}
és több lekérdezést is kiad:
var query1 = context.Entities.Where(e => e.Id == e.Int);
var query2 = context.Entities.Where(e => e.Id == e.NullableInt);
var query3 = context.Entities.Where(e => e.Id != e.NullableInt);
var query4 = context.Entities.Where(e => e.String1 == e.String2);
var query5 = context.Entities.Where(e => e.String1 != e.String2);
Az első két lekérdezés egyszerű összehasonlítást eredményez. Az első lekérdezésben mindkét oszlop nem null értékű, ezért nincs szükség null értékű ellenőrzésekre. A második lekérdezésben NullableInt tartalmazhat null, de Id nem lehet null értékű; null összehasonlítása a nem null értékűvel null eredményt ad, amelyet a WHERE művelettel szűrnének ki. Tehát nincs szükség további feltételekre sem.
SELECT [e].[Id], [e].[Int], [e].[NullableInt], [e].[String1], [e].[String2]
FROM [Entities] AS [e]
WHERE [e].[Id] = [e].[Int]
SELECT [e].[Id], [e].[Int], [e].[NullableInt], [e].[String1], [e].[String2]
FROM [Entities] AS [e]
WHERE [e].[Id] = [e].[NullableInt]
A harmadik lekérdezés null értékű ellenőrzést vezet be. Amikor NullableInt megegyezik null-vel, az összehasonlítás eredménye Id <> NullableIntnull, amit a WHERE művelettel kiszűrünk. Logikai szempontból azonban ezt az esetet az eredmény részeként kell visszaadni. Ezért az EF Core hozzáadja a szükséges ellenőrzést ennek biztosításához.
SELECT [e].[Id], [e].[Int], [e].[NullableInt], [e].[String1], [e].[String2]
FROM [Entities] AS [e]
WHERE ([e].[Id] <> [e].[NullableInt]) OR [e].[NullableInt] IS NULL
A négyes és az öt lekérdezés azt a mintát jeleníti meg, amikor mindkét oszlop null értékű. Érdemes megjegyezni, hogy a <> művelet bonyolultabb (és esetleg lassabb) lekérdezést eredményez, mint a == művelet.
SELECT [e].[Id], [e].[Int], [e].[NullableInt], [e].[String1], [e].[String2]
FROM [Entities] AS [e]
WHERE ([e].[String1] = [e].[String2]) OR ([e].[String1] IS NULL AND [e].[String2] IS NULL)
SELECT [e].[Id], [e].[Int], [e].[NullableInt], [e].[String1], [e].[String2]
FROM [Entities] AS [e]
WHERE (([e].[String1] <> [e].[String2]) OR ([e].[String1] IS NULL OR [e].[String2] IS NULL)) AND ([e].[String1] IS NOT NULL OR [e].[String2] IS NOT NULL)
Null értékű értékek kezelése függvényekben
Az SQL számos függvénye csak akkor tud eredményt adninull, ha az argumentumok egy része .null Az EF Core ezt kihasználva hatékonyabb lekérdezéseket hoz létre.
Az alábbi lekérdezés az optimalizálást szemlélteti:
var query = context.Entities.Where(e => e.String1.Substring(0, e.String2.Length) == null);
A létrehozott SQL a következő (nem kell kiértékelnünk a SUBSTRING függvényt, mivel csak akkor lesz null, ha az argumentumok bármelyike null értékű):
SELECT [e].[Id], [e].[Int], [e].[NullableInt], [e].[String1], [e].[String2]
FROM [Entities] AS [e]
WHERE [e].[String1] IS NULL OR [e].[String2] IS NULL
Az optimalizálás felhasználó által definiált függvényekhez is használható. További részletekért tekintse meg a felhasználó által definiált függvényleképezési oldalt.
Teljesítmő lekérdezések írása
A nem null értékű oszlopok összehasonlítása egyszerűbb és gyorsabb, mint a null értékű oszlopok összehasonlítása. Ha lehetséges, fontolja meg az oszlopok nem null értékűként való megjelölését.
Az egyenlőség (
==) ellenőrzése egyszerűbb és gyorsabb, mint a nem egyenlőség (!=), mert a lekérdezésnek nem kell különbséget tennie az eredmények és aznulleredmények közöttfalse. Ha lehetséges, használjon egyenlőség-összehasonlítást. Azonban, ha egyszerűen tagadjuk az==összehasonlítást, az hatékonyan ugyanaz, mint a!=, így nem eredményez teljesítményjavulást.Bizonyos esetekben egyszerűbbé teheti az összetett összehasonlítást, ha explicit módon szűri ki
nullaz értékeket egy oszlopból – például ha nincseneknullértékek, vagy ezek az értékek nem relevánsak az eredményben. Vegye figyelembe a következő példát:
var query1 = context.Entities.Where(e => e.String1 != e.String2 || e.String1.Length == e.String2.Length);
var query2 = context.Entities.Where(
e => e.String1 != null && e.String2 != null && (e.String1 != e.String2 || e.String1.Length == e.String2.Length));
Ezek a lekérdezések a következő SQL-t állítják elő:
SELECT [e].[Id], [e].[Int], [e].[NullableInt], [e].[String1], [e].[String2]
FROM [Entities] AS [e]
WHERE ((([e].[String1] <> [e].[String2]) OR ([e].[String1] IS NULL OR [e].[String2] IS NULL)) AND ([e].[String1] IS NOT NULL OR [e].[String2] IS NOT NULL)) OR ((CAST(LEN([e].[String1]) AS int) = CAST(LEN([e].[String2]) AS int)) OR ([e].[String1] IS NULL AND [e].[String2] IS NULL))
SELECT [e].[Id], [e].[Int], [e].[NullableInt], [e].[String1], [e].[String2]
FROM [Entities] AS [e]
WHERE ([e].[String1] IS NOT NULL AND [e].[String2] IS NOT NULL) AND (([e].[String1] <> [e].[String2]) OR (CAST(LEN([e].[String1]) AS int) = CAST(LEN([e].[String2]) AS int)))
A második lekérdezésben az eredményeket a String1 oszlopból expliciten kiszűrik. Az EF Core az összehasonlítás során biztonságosan nem null értékűként kezeli az String1 oszlopot, ami egyszerűbb lekérdezést eredményez.
Relációs null szemantikák használata
Letilthatja a null összehasonlító kompenzációt, és közvetlenül használhat relációs null szemantikát. Ezt úgy teheti meg, hogy meghívja UseRelationalNulls(true) a metódust a beállításszerkesztőben a metóduson belül OnConfiguring :
new SqlServerDbContextOptionsBuilder(optionsBuilder).UseRelationalNulls();
Figyelmeztetés
A relációs null szemantikák használatakor a LINQ-lekérdezések már nem rendelkeznek ugyanazzal a jelentéssel, mint a C#-ban, és a várttól eltérő eredményeket eredményezhetnek. Ezzel a móddal óvatosan járjon el.