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.
Giriş
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 değer atanamaz, bu nedenle null denetimler gerekli değildir. İkinci sorguda içerebilir NullableInt null, ancak Id null değer atanamaz; sonuç olarak null olmayan verimlerle null karşılaştırılarak null işlem tarafından WHERE 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 neden oldu. Karşılaştırma, işlemine göre filtrelenecek WHERE olan verimleri nullolduğunda NullableInt null.Id <> NullableInt 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ört ve beş sorgular, her iki sütun da null atanabilir olduğunda deseni gösterir. İşlemin <> , işlemden daha karmaşık (ve potansiyel olarak daha yavaş) sorgu ürettiğine == dikkat edin.
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 bağımsız değişkenlerinden nullbazıları ise sonuç null 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 (işlevi değerlendirmemiz SUBSTRING gerekmez çünkü bağımsız değişkenlerden biri null olduğunda yalnızca null olur.):
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.
Performans gösteren 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. Mümkün olduğunda sütunları null atanamaz olarak işaretlemeyi göz önünde bulundurun.
Eşitlik (
==) denetimi, eşitlik dışı!=( denetiminden daha basit ve hızlıdır), çünkü sorgu ile sonucu birbirindennullfalseayı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 değerleri açıkça filtreleyerek
nullkarmaşık bir karşılaştırmayı basitleştirmek mümkündür; örneğin, değer olmadığındanullveya bu değerler sonuçla ilgili olmadığında. Aşağıdaki örneği göz önünde bulundurun:
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 sonuçlar sütundan null String1 açıkça filtrelenir. EF Core, karşılaştırma sırasında sütunu null değer atanamaz olarak güvenli bir şekilde değerlendirerek String1 daha basit bir sorgu elde edebilir.
İ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 işlem, yöntemin içindeki OnConfiguring seçenekler oluşturucusunun yöntemini çağırarak UseRelationalNulls(true) 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.