Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Introduction
SQL veritabanları, C# boole mantığının aksine karşılaştırmalar gerçekleştirirken 3 değerli mantık (true, false, null) üzerinde çalışır. EF Core, LINQ sorgularını SQL'e çevirirken, sorgunun bazı öğeleri için ek null denetimleri ekleyerek farkı telafi etmeye çalışır.
Bunu göstermek için aşağıdaki varlığı tanımlayalım:
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 oluşturun:
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 oluşturur. İlk sorguda, her iki sütun da null olamaz, bu nedenle null denetimi yapmaya gerek yoktur. İkinci sorguda, NullableIntnull içerebilir, ancak Id null olamaz; null'ü null olmayan bir değere karşılaştırmak null sonucunu verir ve bu, WHERE işlemi tarafından filtrelenecektir. 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 bir null denetimi tanıtıyor.
NullableInt
null olduğunda, karşılaştırma Id <> NullableIntnull verir, ki bu durum WHERE işlemi tarafından filtrelenecektir. Ancak boole mantığı açısından bu durum sonucun bir parçası olarak döndürülmelidir. Bu nedenle EF Core, bunu sağlamak 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ördüncü ve beşinci sorgular, her iki sütunun da null değer alabilir olduğunda deseni gösterir.
<> işleminin == işlemine göre daha karmaşık (ve potansiyel olarak daha yavaş) sorgu ürettiğine dikkat etmek gerekir.
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)
İşlevlerdeki null atanabilir değerlerin işlenmesi
SQL'deki birçok işlev, yalnızca bazı bağımsız değişkenleri null olduğunda null sonucu döndürebilir. EF Core, daha verimli sorgular üretmek için bundan yararlanır.
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 (SUBSTRING işlevini değerlendirmemiz gerekmez çünkü bağımsız değişkenlerden biri "null" olduğunda sonuç yalnızca "null" olacaktır.):
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 kullanıcı tanımlı işlev eşleme sayfasına bakın.
Yüksek performanslı sorgular yazma
Null değer atanamayan sütunları karşılaştırmak, null atanabilir sütunları karşılaştırmaktan daha basit ve daha hızlıdır. Sütunları mümkün olduğunda null olamaz olarak işaretlemeyi düşünün.
Eşitlik kontrolü (
==), eşit olmama kontrolünden (!=) daha basit ve hızlıdır, çünkü sorgu,nullvefalsesonuçlarını birbirinden ayırt etmek zorunda değildir. Mümkün olduğunda eşitlik karşılaştırması kullanın. Ancak karşılaştırmanın olumsuzlaştırılması==ile etkili bir şekilde aynıdır!=, bu nedenle performans artışına neden olmaz.Bazı durumlarda, bir sütundaki
nulldeğerlerini açıkça filtreleyerek karmaşık bir karşılaştırmayı basitleştirmek mümkündür; örneğin,nulldeğerleri olmadığında veya bu değerler sonuca ilişkin olmadığında. 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'i oluşturur:
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, null sonuçları String1 sütunundan açıkça filtrelenir. EF Core, karşılaştırma sırasında String1 sütununu null değer atanamaz sütun olarak güvenli bir şekilde değerlendirebilir ve bu da daha basit bir sorgu oluşturabilir.
İ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, OnConfiguring metodunun içindeki seçenekler oluşturucusu üzerinde UseRelationalNulls(true) metodunu çağırarak yapılabilir.
new SqlServerDbContextOptionsBuilder(optionsBuilder).UseRelationalNulls();
Uyarı
İlişkisel null semantiği kullanırken, LINQ sorgularınızın artık C# ile aynı anlamı yoktur ve beklenenden farklı sonuçlar verebilir. Bu modu kullanırken dikkatli olun.