Null semantiği sorgulama
Giriş
SQL truefalse veritabanları, C# boole mantığının aksine karşılaştırmalar yaparken 3 değerli mantık ( , , ) üzerinde null çalışır. LINQ sorgularını veri SQL EF Core, sorgunun bazı öğeleri için ek null denetimleri göndererek farkı telafi etmeye çalışır.
Bunu göstermek için aşağıdaki varlığı tanımlayabilirsiniz:
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; }
}
ve birkaç sorgu sorun:
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);
İlk iki sorgu basit karşılaştırmalar üretir. İlk sorguda her iki sütun da null değere geçirilemez, bu nedenle null denetimlere gerek yoktur. İkinci sorguda içerebilir, ancak null olamaz; sonuç olarak null olmayan verimlerle karşılaştırılarak işlem tarafından NullableIntnullIdnullnullWHERE filtrelenebilir. Bu nedenle ek koşullar da gerekli değildir.
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]
Üçüncü sorgu null denetime giriştir. NullableIntKarşılaştırmanın nullId <> NullableInt verimi null olduğunda, bu işlem tarafından WHERE filtrelenmiş olur. Ancak boole mantığı açısından bu durum, sonucun bir parçası olarak döndürüldü. Bu EF Core emin olmak için gerekli denetimi ekler.
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
Dört ve beş sorgu, her iki sütun da null değere sahip olduğunda deseni gösterir. Bu işlem, işlemden daha karmaşık (ve daha <> yavaş) sorgu == üretir.
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)
İşlevlerde null değerlerle ilgili tedavi
bu SQL işlevleri yalnızca bağımsız null değişkenlerinden bazıları ise sonuç null getirebilirsiniz. EF Core daha verimli sorgular oluşturmak için bundan faydalanıyor.
Aşağıdaki sorgu iyileştirmeyi gösterir:
var query = context.Entities.Where(e => e.String1.Substring(0, e.String2.Length) == null);
Oluşturulan SQL aşağıdaki gibidir (yalnızca bağımsız değişkenlerden biri null olduğunda null olacağını için işlevi SUBSTRING değerlendirmemiz gerek yoktur.):
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
İyileştirme, kullanıcı tanımlı işlevler için de kullanılabilir. Daha fazla ayrıntı için bkz. kullanıcı tanımlı işlev eşleme sayfası.
Performansa göre sorgu yazma
Null değere sahip olmayan sütunları karşılaştırmak null değere değiştirilebilir sütunları karşılaştırmaktan daha basittir ve daha hızlıdır. Mümkün olduğunda sütunları null değer olarak işaretlemeyi göz önünde bulundurabilirsiniz.
Sorgunun ile sonucu ayırt etmek zorunda olmadığını çünkü eşitlik ( ) denetiminden daha basit ve
==!=dahanullhızlıdır.falseMümkün olduğunda eşitlik karşılaştırması kullanın. Ancak, karşılaştırmayı olumsuzlama ile etkili bir şekilde==!=aynıdır, bu nedenle performans geliştirmesine neden değildir.Bazı durumlarda, bir sütundaki değerleri açıkça filtreleerek karmaşık bir karşılaştırmayı basitleştirmek mümkündür. Örneğin, değer mevcut olduğunda veya bu değerler sonuçta ilgili
nullnulldeğildir. Aşağıdaki örneği inceleyin:
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));
Bu sorgular aşağıdaki SQL:
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)))
İkinci sorguda sonuçlar null sütundan açıkça String1 filtrelenmiş olur. EF Core, karşılaştırma sırasında String1 sütunu güvenli bir şekilde null değersiz olarak işlenebilir ve bu da daha basit bir sorguyla sonuçlanabilir.
İlişkisel null semantiği kullanma
Null karşılaştırma telafisini devre dışı bırakmak ve ilişkisel null semantiği doğrudan kullanmak mümkündür. Bu, yönteminin içindeki UseRelationalNulls(true) seçenekler oluşturucusu üzerinde yöntemi çağrılarak OnConfiguring yapılabilir:
new SqlServerDbContextOptionsBuilder(optionsBuilder).UseRelationalNulls();
Uyarı
İlişkisel null semantik kullanırken LINQ sorgularınız artık C# ile aynı anlama sahip değildir ve beklenenden farklı sonuçlar döndürebilecektir. Bu modu kullanırken dikkatli olun.