Karmaşık Sorgu İşleçleriComplex Query Operators

Dil Tümleşik Sorgusu (LINQ), birden çok veri kaynağını birleştiren veya karmaşık işleme yapan birçok karmaşık işleç içerir.Language Integrated Query (LINQ) contains many complex operators, which combine multiple data sources or does complex processing. Tüm LINQ operatörleri sunucu tarafında uygun çevirilere sahip değildir.Not all LINQ operators have suitable translations on the server side. Bazen, bir formdaki bir sorgu sunucuya çevirir, ancak farklı bir biçimde yazılmışsa, sonuç aynı olsa bile çevrilemez.Sometimes, a query in one form translates to the server but if written in a different form doesn't translate even if the result is the same. Bu sayfa, bazı karmaşık işleçleri ve desteklenen varyasyonlarını açıklar.This page describes some of the complex operators and their supported variations. Gelecek sürümlerde, daha fazla desen tanıyabilir ve karşılık gelen çevirileri ekleyebilirsiniz.In future releases, we may recognize more patterns and add their corresponding translations. Çeviri desteğinin sağlayıcılar arasında farklılık gösterdiğini de unutmayın.It's also important to keep in mind that translation support varies between providers. SqlServer'da çevrilen belirli bir sorgu, SQLite veritabanları için çalışmayabilir.A particular query, which is translated in SqlServer, may not work for SQLite databases.

İpucu

Bu makalenin örneğini GitHub'da görüntüleyebilirsiniz.You can view this article's sample on GitHub.

BirleştirJoin

LINQ Join işleci, her kaynak için anahtar seçiciyi temel alan iki veri kaynağını bağlamanızı sağlar ve anahtar eşleştiğinde bir dizi değer oluşturur.The LINQ Join operator allows you to connect two data sources based on the key selector for each source, generating a tuple of values when the key matches. Doğal olarak ilişkisel INNER JOIN veritabanlarına çevirir.It naturally translates to INNER JOIN on relational databases. LINQ Join'in dış ve iç anahtar seçicileri olsa da, veritabanı tek bir birleştirme koşulu gerektirir.While the LINQ Join has outer and inner key selectors, the database requires a single join condition. Böylece EF Core, dış anahtar seçiciyi eşitlik için iç anahtar seçiciyle karşılaştırarak bir birleştirme koşulu oluşturur.So EF Core generates a join condition by comparing the outer key selector to the inner key selector for equality. Ayrıca, anahtar seçiciler anonim türlerise, EF Core eşitlik bileşenini akıllıca karşılaştırmak için bir birleştirme koşulu oluşturur.Further, if the key selectors are anonymous types, EF Core generates a join condition to compare equality component wise.

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]

GroupjoinGroupJoin

LINQ GroupJoin işleci Birleştirme'ye benzer iki veri kaynağını bağlamanızı sağlar, ancak dış öğeleri eşleştirmek için bir iç değer grubu oluşturur.The LINQ GroupJoin operator allows you to connect two data sources similar to Join, but it creates a group of inner values for matching outer elements. Aşağıdaki örnek gibi bir sorgu yürütme bir Blog & IEnumerable<Post>sonucu oluşturur .Executing a query like the following example generates a result of Blog & IEnumerable<Post>. Veritabanlarının (özellikle ilişkisel veritabanları) istemci tarafındaki nesnelerin bir koleksiyonunu temsil etmenin bir yolu olmadığından, GroupJoin birçok durumda sunucuya çevrilmez.Since databases (especially relational databases) don't have a way to represent a collection of client-side objects, GroupJoin doesn't translate to the server in many cases. Özel bir seçici olmadan GroupJoin yapmak için sunucudan tüm verileri almak için gerektirir (aşağıdaki ilk sorgu).It requires you to get all of the data from the server to do GroupJoin without a special selector (first query below). Ancak seçici seçili verileri sınırlıyorsa, tüm verileri sunucudan almak performans sorunlarına (aşağıdaki ikinci sorgu) neden olabilir.But if the selector is limiting data being selected then fetching all of the data from the server may cause performance issues (second query below). Bu yüzden EF Core GroupJoin'i tercüme etmez.That's why EF Core doesn't translate GroupJoin.

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() };

SelectmanySelectMany

LINQ SelectMany işleci, her dış öğe için bir koleksiyon seçici üzerinde sayısaloluşturmanıza ve her veri kaynağından değer tuples oluşturmanıza olanak tanır.The LINQ SelectMany operator allows you to enumerate over a collection selector for each outer element and generate tuples of values from each data source. Bir bakıma, bu bir birleştirme ama her dış öğe toplama kaynağından bir öğe ile bağlı böylece herhangi bir koşul olmadan.In a way, it's a join but without any condition so every outer element is connected with an element from the collection source. Toplama seçicinin dış veri kaynağıyla nasıl ilişkili olduğuna bağlı olarak, SelectMany sunucu tarafında çeşitli sorgulara çevrilebilir.Depending on how the collection selector is related to the outer data source, SelectMany can translate into various different queries on the server side.

Koleksiyon seçici dış başvuru yokCollection selector doesn't reference outer

Koleksiyon seçici dış kaynaktan bir şey atıfta bulunmuyorsa, sonuç her iki veri kaynağının kartezyen ürünüdür.When the collection selector isn't referencing anything from the outer source, the result is a cartesian product of both data sources. Bu ilişkisel CROSS JOIN veritabanları çevirir.It translates to CROSS JOIN in relational databases.

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]

Toplama seçici referansları bir yer yan tümcesi dışCollection selector references outer in a where clause

Koleksiyon seçici, dış öğeye başvurulan bir where yan tümcesi olduğunda, EF Core bunu bir veritabanı birleştirmesine çevirir ve yüklemi birleştirme koşulu olarak kullanır.When the collection selector has a where clause, which references the outer element, then EF Core translates it to a database join and uses the predicate as the join condition. Normalde bu durum, koleksiyon seçici olarak dış öğeüzerinde toplama gezintisi kullanırken ortaya çıkar.Normally this case arises when using collection navigation on the outer element as the collection selector. Koleksiyon bir dış öğe için boşsa, bu dış öğe için hiçbir sonuç oluşturulur.If the collection is empty for an outer element, then no results would be generated for that outer element. Ancak DefaultIfEmpty koleksiyon seçiciye uygulanırsa, dış öğe iç öğenin varsayılan değeriyle bağlanır.But if DefaultIfEmpty is applied on the collection selector then the outer element will be connected with a default value of the inner element. Bu ayrım nedeniyle, bu tür sorgular INNER JOIN yokluğunda DefaultIfEmpty ve LEFT JOIN ne DefaultIfEmpty zaman uygulanır çevirir.Because of this distinction, this kind of queries translates to INNER JOIN in the absence of DefaultIfEmpty and LEFT JOIN when DefaultIfEmpty is applied.

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, olmayan bir durumda dış başvurularCollection selector references outer in a non-where case

Koleksiyon seçici, bir where yan tümcesinde olmayan dış öğeye (yukarıdaki gibi) başvurursa, veritabanı birleştirmesine çevrilmez.When the collection selector references the outer element, which isn't in a where clause (as the case above), it doesn't translate to a database join. Bu nedenle her dış öğe için koleksiyon seçiciyi değerlendirmemiz gerekir.That's why we need to evaluate the collection selector for each outer element. Birçok ilişkisel APPLY veritabanlarındaki işlemlere çevirir.It translates to APPLY operations in many relational databases. Koleksiyon bir dış öğe için boşsa, bu dış öğe için hiçbir sonuç oluşturulur.If the collection is empty for an outer element, then no results would be generated for that outer element. Ancak DefaultIfEmpty koleksiyon seçiciye uygulanırsa, dış öğe iç öğenin varsayılan değeriyle bağlanır.But if DefaultIfEmpty is applied on the collection selector then the outer element will be connected with a default value of the inner element. Bu ayrım nedeniyle, bu tür sorgular CROSS APPLY yokluğunda DefaultIfEmpty ve OUTER APPLY ne DefaultIfEmpty zaman uygulanır çevirir.Because of this distinction, this kind of queries translates to CROSS APPLY in the absence of DefaultIfEmpty and OUTER APPLY when DefaultIfEmpty is applied. SQLite gibi bazı veritabanları operatörleri APPLY desteklemez, bu nedenle bu tür bir sorgu çevrilmeyebilir.Certain databases like SQLite don't support APPLY operators so this kind of query may not be translated.

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]

GroupByGroupBy

LINQ GroupBy işleçleri, IGrouping<TKey, TElement> TKey rasgele TElement bir tür olabileceği ve olabileceği türden bir sonuç oluşturur.LINQ GroupBy operators create a result of type IGrouping<TKey, TElement> where TKey and TElement could be any arbitrary type. Ayrıca, IGrouping uygular IEnumerable<TElement>, gruplama sonra herhangi bir LINQ işleci kullanarak üzerine oluşturabilirsiniz anlamına gelir.Furthermore, IGrouping implements IEnumerable<TElement>, which means you can compose over it using any LINQ operator after the grouping. Hiçbir veritabanı yapısı bir IGroupingtemsil edemediğinden, GroupBy işleçleri çoğu durumda çeviriye sahip değildir.Since no database structure can represent an IGrouping, GroupBy operators have no translation in most cases. Bir skaler döndürür her gruba bir toplam işleç uygulandığında, GROUP BY ilişkisel veritabanlarında SQL'e çevrilebilir.When an aggregate operator is applied to each group, which returns a scalar, it can be translated to SQL GROUP BY in relational databases. SQL GROUP BY de kısıtlayıcıdır.The SQL GROUP BY is restrictive too. Yalnızca skaler değerlere göre gruplandırmanızı gerektirir.It requires you to group only by scalar values. Projeksiyon yalnızca anahtar sütunları veya bir sütun üzerinde uygulanan herhangi bir toplamı gruplandırma içerebilir.The projection can only contain grouping key columns or any aggregate applied over a column. EF Core bu deseni tanımlar ve aşağıdaki örnekte olduğu gibi sunucuya çevirir:EF Core identifies this pattern and translates it to the server, as in the following example:

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 ayrıca, gruplandırmadaki toplam işlecinin bir Where veya OrderBy (veya diğer sipariş) LINQ işlecinde göründüğü sorguları da çevirir.EF Core also translates queries where an aggregate operator on the grouping appears in a Where or OrderBy (or other ordering) LINQ operator. Nerede HAVING yan tümcesi için SQL'deki yan tümceyi kullanır.It uses HAVING clause in SQL for the where clause. GroupBy işleci uygulamadan önce sorgunun bölümü, sunucuya çevrilebildiği sürece karmaşık bir sorgu olabilir.The part of the query before applying the GroupBy operator can be any complex query as long as it can be translated to server. Ayrıca, gruplandırma ları elde edilen kaynaktan kaldırmak için gruplandırma sorgusuna toplu işleçler uyguladığınız da, diğer sorgular gibi bunun üzerine oluşturabilirsiniz.Furthermore, once you apply aggregate operators on a grouping query to remove groupings from the resulting source, you can compose on top of it like any other query.

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]

EF Core desteklerinin toplamı aşağıdaki gibidirThe aggregate operators EF Core supports are as follows

  • OrtalamaAverage
  • SayıCount
  • LongcountLongCount
  • MaksMax
  • MinMin
  • ToplamSum

Sola KatılmaLeft Join

Sol Birleştirme bir LINQ işleci olmasa da, ilişkisel veritabanları sorgularda sık lıkla kullanılan Sol Birleştirme kavramına sahiptir.While Left Join isn't a LINQ operator, relational databases have the concept of a Left Join which is frequently used in queries. LINQ sorgularında belirli bir desen sunucuda LEFT JOIN aynı sonucu verir.A particular pattern in LINQ queries gives the same result as a LEFT JOIN on the server. EF Core bu tür desenleri LEFT JOIN tanımlar ve sunucu tarafında eşdeğer oluşturur.EF Core identifies such patterns and generates the equivalent LEFT JOIN on the server side. Desen, hem veri kaynakları arasında bir GroupJoin oluşturmayı ve sonra selectmany işlecinin içinin ilgili bir öğesi olmadığında null'u eşleştirmek için gruplandırma kaynağında DefaultIfEmpty ile birlikte gruplandırmayı düzleştirmekten içerir.The pattern involves creating a GroupJoin between both the data sources and then flattening out the grouping by using the SelectMany operator with DefaultIfEmpty on the grouping source to match null when the inner doesn't have a related element. Aşağıdaki örnek, bu örünteğin neye benzediğini ve ne ürettiğini gösterir.The following example shows what that pattern looks like and what it generates.

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.The above pattern creates a complex structure in the expression tree. Bu nedenle, EF Core, GroupJoin işlecinin gruplandırma sonuçlarını operatörü hemen izleyen bir adımda düzleştirir.Because of that, EF Core requires you to flatten out the grouping results of the GroupJoin operator in a step immediately following the operator. GroupJoin-DefaultIfEmpty-SelectMany kullanılsa bile, ancak farklı bir desende, onu Sol Birleştirme olarak tanımlayamayabiliriz.Even if the GroupJoin-DefaultIfEmpty-SelectMany is used but in a different pattern, we may not identify it as a Left Join.