Karmaşık Sorgu İşleçleri
Language Integrated Query (LINQ), birden çok veri kaynağı birleştiren veya karmaşık işleme işlemi gerçekleştiren birçok karmaşık işleç içerir. Tüm LINQ işleçleri sunucu tarafında uygun çevirilere sahip değildir. Bazen, tek bir formda sorgu sunucuya çevrilir, ancak farklı bir formda yazılmışsa, sonuç aynı olsa bile çevrilebilir. Bu sayfada bazı karmaşık işleçler ve bunların desteklenen varyasyonları açıklandı. Gelecek sürümlerde daha fazla desen tanıyacak ve karşılık gelen çevirilerini ekleyeceğiz. Çeviri desteğinin sağlayıcılar arasında değişiklik olduğunu da unutmayın. SqlServer'da çevrilen belirli bir sorgu, SQLite veritabanları için çalışmayabilirsiniz.
İpucu
Bu makalenin örneğini daha sonra GitHub.
Katılın
LINQ Join işleci, her bir kaynak için anahtar seçiciyi temel alan iki veri kaynağını bağlamanıza olanak sağlar ve anahtar eşlence değerlerden bir kayıt oluşturma. doğal olarak ilişkisel INNER JOIN veritabanlarında olarak çevrilir. LINQ Join dış ve iç anahtar seçicileri içerir ancak veritabanı için tek bir birleşim koşulu gerekir. Bu EF Core dış anahtar seçiciyi eşitlik için iç anahtar seçiciyle karşılaştırarak bir birleştirme koşulu üretir.
var query = from photo in context.Set<PersonPhoto>()
join person in context.Set<Person>()
on photo.PersonPhotoId equals person.PhotoId
select new { person, photo };
SELECT [p].[PersonId], [p].[Name], [p].[PhotoId], [p0].[PersonPhotoId], [p0].[Caption], [p0].[Photo]
FROM [PersonPhoto] AS [p0]
INNER JOIN [Person] AS [p] ON [p0].[PersonPhotoId] = [p].[PhotoId]
Ayrıca, anahtar seçiciler anonim türlerse EF Core bileşen açısından karşılaştırmak için bir birleştirme koşulu oluşturulur.
var query = from photo in context.Set<PersonPhoto>()
join person in context.Set<Person>()
on new { Id = (int?)photo.PersonPhotoId, photo.Caption }
equals new { Id = person.PhotoId, Caption = "SN" }
select new { person, photo };
SELECT [p].[PersonId], [p].[Name], [p].[PhotoId], [p0].[PersonPhotoId], [p0].[Caption], [p0].[Photo]
FROM [PersonPhoto] AS [p0]
INNER JOIN [Person] AS [p] ON ([p0].[PersonPhotoId] = [p].[PhotoId] AND ([p0].[Caption] = N'SN'))
Groupjoin
LINQ GroupJoin işleci Join'e benzer iki veri kaynağı bağlamanıza olanak sağlar, ancak dış öğeleri eşleştirmek için bir iç değer grubu oluşturur. Aşağıdaki örnekte olduğu gibi bir sorgunun yürütülmesi sonucu Blog&IEnumerable<Post> oluşturur. Veritabanlarının (özellikle ilişkisel veritabanları) istemci tarafı nesneleri koleksiyonunu temsil etmek için bir yolu olmadığını için GroupJoin birçok durumda sunucuya çevrilebilir. GroupJoin'i özel seçici olmadan yapmak için sunucudan tüm verileri alısınız (aşağıdaki ilk sorgu). Ancak seçici seçilen verileri sınırlandırıyorsa tüm verilerin sunucudan getirilebiliyor olması performans sorunlarına neden olabilir (aşağıdaki ikinci sorgu). Bu nedenle EF Core GroupJoin'i çevirmez.
var query = from b in context.Set<Blog>()
join p in context.Set<Post>()
on b.BlogId equals p.PostId into grouping
select new { b, grouping };
var query = from b in context.Set<Blog>()
join p in context.Set<Post>()
on b.BlogId equals p.PostId into grouping
select new { b, Posts = grouping.Where(p => p.Content.Contains("EF")).ToList() };
Selectmany
LINQ SelectMany işleci, her dış öğe için bir koleksiyon seçicisi üzerinde numara seçmenize ve her veri kaynağından değer çiftleri oluşturmana olanak sağlar. Bir şekilde birleşimdir, ancak koşulsuzdur, bu nedenle her dış öğe koleksiyon kaynağından bir öğeyle bağlanır. Koleksiyon seçicinin dış veri kaynağıyla nasıl ilişkili olduğuna bağlı olarak, SelectMany sunucu tarafında farklı sorgulara çevrilebilir.
Koleksiyon seçici dış başvuruyor
Koleksiyon seçici dış kaynaktan herhangi bir şeye başvurmasa, sonuç her iki veri kaynağının kartesyen bir ürünüdür. İlişkisel CROSS JOIN veritabanlarında olarak çevrilir.
var query = from b in context.Set<Blog>()
from p in context.Set<Post>()
select new { b, p };
SELECT [b].[BlogId], [b].[OwnerId], [b].[Rating], [b].[Url], [p].[PostId], [p].[AuthorId], [p].[BlogId], [p].[Content], [p].[Rating], [p].[Title]
FROM [Blogs] AS [b]
CROSS JOIN [Posts] AS [p]
Where yan tümcesinde dışta koleksiyon seçici başvuruları
Koleksiyon seçicide dış öğeye başvurulan bir where yan tümcesi olduğunda, EF Core bunu bir veritabanı birleştirmesine çevirir ve birleştirme koşulu olarak koşulu kullanır. Normalde bu durum, koleksiyon seçici olarak dış öğede koleksiyon gezintisi kullanılırken ortaya çıkar. Koleksiyon dış öğe için boşsa, bu dış öğe için sonuç oluşturulmaz. Ancak DefaultIfEmpty koleksiyon seçiciye uygulanırsa dış öğe, iç öğenin varsayılan değeriyle bağlanır. Bu ayrım nedeniyle bu tür sorgular, ve ne zaman INNER JOINDefaultIfEmpty uygulanmazsa LEFT JOIN ile DefaultIfEmpty çevrilir.
var query = from b in context.Set<Blog>()
from p in context.Set<Post>().Where(p => b.BlogId == p.BlogId)
select new { b, p };
var query2 = from b in context.Set<Blog>()
from p in context.Set<Post>().Where(p => b.BlogId == p.BlogId).DefaultIfEmpty()
select new { b, p };
SELECT [b].[BlogId], [b].[OwnerId], [b].[Rating], [b].[Url], [p].[PostId], [p].[AuthorId], [p].[BlogId], [p].[Content], [p].[Rating], [p].[Title]
FROM [Blogs] AS [b]
INNER JOIN [Posts] AS [p] ON [b].[BlogId] = [p].[BlogId]
SELECT [b].[BlogId], [b].[OwnerId], [b].[Rating], [b].[Url], [p].[PostId], [p].[AuthorId], [p].[BlogId], [p].[Content], [p].[Rating], [p].[Title]
FROM [Blogs] AS [b]
LEFT JOIN [Posts] AS [p] ON [b].[BlogId] = [p].[BlogId]
Koleksiyon seçici başvuruları, where olmayan bir durumda dışta
Koleksiyon seçici where yan tümcesinde yer alan dış öğeye başvursa (yukarıdaki durumda olduğu gibi), veritabanı birleştirmesine çevrililmez. Bu nedenle dıştaki her öğe için koleksiyon seçicisini değerlendirmemiz gerekir. Birçok ilişkisel APPLY veritabanındaki işlemlere çevrilir. Koleksiyon dış öğe için boşsa, bu dış öğe için sonuç oluşturulmaz. Ancak DefaultIfEmpty koleksiyon seçiciye uygulanırsa dış öğe, iç öğenin varsayılan değeriyle bağlanır. Bu ayrım nedeniyle bu tür sorgular, ve ne zaman CROSS APPLYDefaultIfEmpty uygulanmazsa OUTER APPLY ile DefaultIfEmpty çevrilir. SQLite gibi bazı veritabanları APPLY işleçleri desteklemez, bu nedenle bu tür bir sorgu çevrilenemebilir.
var query = from b in context.Set<Blog>()
from p in context.Set<Post>().Select(p => b.Url + "=>" + p.Title)
select new { b, p };
var query2 = from b in context.Set<Blog>()
from p in context.Set<Post>().Select(p => b.Url + "=>" + p.Title).DefaultIfEmpty()
select new { b, p };
SELECT [b].[BlogId], [b].[OwnerId], [b].[Rating], [b].[Url], ([b].[Url] + N'=>') + [p].[Title] AS [p]
FROM [Blogs] AS [b]
CROSS APPLY [Posts] AS [p]
SELECT [b].[BlogId], [b].[OwnerId], [b].[Rating], [b].[Url], ([b].[Url] + N'=>') + [p].[Title] AS [p]
FROM [Blogs] AS [b]
OUTER APPLY [Posts] AS [p]
GroupBy
LINQ GroupBy işleçleri, ve herhangi bir rastgele IGrouping<TKey, TElement>TKeyTElement türün türünden bir sonuç oluşturabilir. Ayrıca, IGroupingIEnumerable<TElement> uygulanır; başka bir anlama gelir, gruplamadan sonra herhangi bir LINQ işleci kullanarak bu işleç üzerinde oluşturmuş oluruz. Hiçbir veritabanı yapısı bir temsili IGrouping yapıya sahip olaya, GroupBy işleçleri çoğu durumda çeviriye sahip değildir. Her gruba skaler değer döndüren bir toplama işleci uygulandığında, ilişkisel veritabanlarında SQL GROUP BY işlecine çevrilebilir. Bu SQL GROUP BY da kısıtlayıcıdır. Yalnızca skaler değerlere göre gruplatırsınız. Projeksiyon yalnızca gruplama anahtar sütunlarını veya bir sütuna uygulanan toplamaları içerebilir. EF Core düzeni tanımlar ve aşağıdaki örnekte olduğu gibi sunucuya çevirir:
var query = from p in context.Set<Post>()
group p by p.AuthorId
into g
select new { g.Key, Count = g.Count() };
SELECT [p].[AuthorId] AS [Key], COUNT(*) AS [Count]
FROM [Posts] AS [p]
GROUP BY [p].[AuthorId]
EF Core, gruplama üzerinde bir toplama işlecinin Where veya OrderBy (veya diğer sıralama) LINQ işlecinde göründüğü sorguları da çevirir. Where yan HAVING tümcesi SQL içinde yan tümcesini kullanır. GroupBy işleci uygulamadan önce sorgunun parçası, sunucuya çevrilebilir olduğu sürece herhangi bir karmaşık sorgu olabilir. Ayrıca, toplama işleçlerini bir gruplama sorgusuna, sonuçta elde edilen kaynaktan gruplamaları kaldırmak için uygulatarak bunun üzerinde diğer sorgular gibi bir oluşturma gerçekleştirebilirsiniz.
var query = from p in context.Set<Post>()
group p by p.AuthorId
into g
where g.Count() > 0
orderby g.Key
select new { g.Key, Count = g.Count() };
SELECT [p].[AuthorId] AS [Key], COUNT(*) AS [Count]
FROM [Posts] AS [p]
GROUP BY [p].[AuthorId]
HAVING COUNT(*) > 0
ORDER BY [p].[AuthorId]
Tarafından EF Core toplama işleçleri aşağıdaki gibidir
- Ortalama
- Count
- Longcount
- En yüksek değer
- Min
- Sum
Sol Birleştirme
Sol Birleştirme linq işleci değildir ancak ilişkisel veritabanlarında sorgularda sıklıkla kullanılan Bir Sol Birleşim kavramı vardır. LINQ sorgularında belirli bir desen, sunucu üzerinde bir ile LEFT JOIN aynı sonucu verir. EF Core desenleri tanımlar ve sunucu tarafında LEFT JOIN eşdeğerini üretir. Desen, her iki veri kaynağı arasında bir GroupJoin oluşturmayı ve ardından iç öğe ilgili bir öğeye sahip değilken null ile eşleşmek için gruplama kaynağında DefaultIfEmpty ile SelectMany işleci kullanarak gruplama düz hale gelir. Aşağıdaki örnek, bu desenin nasıl göründüğünü ve ne üret yaptığını gösterir.
var query = from b in context.Set<Blog>()
join p in context.Set<Post>()
on b.BlogId equals p.BlogId into grouping
from p in grouping.DefaultIfEmpty()
select new { b, p };
SELECT [b].[BlogId], [b].[OwnerId], [b].[Rating], [b].[Url], [p].[PostId], [p].[AuthorId], [p].[BlogId], [p].[Content], [p].[Rating], [p].[Title]
FROM [Blogs] AS [b]
LEFT JOIN [Posts] AS [p] ON [b].[BlogId] = [p].[BlogId]
Yukarıdaki desen, ifade ağacında karmaşık bir yapı oluşturur. Bu nedenle, EF Core işlecinin hemen ardından bir adımda GroupJoin işlecinin gruplama sonuçlarını düzden çıkarmalısınız. GroupJoin-DefaultIfEmpty-SelectMany farklı bir desende kullanılıyor olsa bile, bunu Sol Birleşim olarak tanımlamay adımız bile olmaz.