EF Core (Entity Framework Core) ile iki tabloyu birleştirmek için LINQ Join operatörünü, gruplayıp sayım veya toplam almak için GroupBy operatörünü kullanırsınız; EF Core bunları SQL tarafında INNER JOIN, GROUP BY ve HAVING olarak çevirir. Sol birleştirme (LEFT JOIN) için ise EF Core 10 ile birlikte .NET 10'un yeni LeftJoin operatörünü doğrudan yazabilirsiniz; daha eski sürümlerde bunun yolu GroupJoin, SelectMany ve DefaultIfEmpty üçlüsünden oluşan belirli bir kalıptı.

Bu yazıda karmaşık sorgu operatörlerinin hangi biçimlerinin sunucuda çalışan SQL'e çevrildiğini, hangilerinin çevrilemediğini ve neden çevrilemediğini resmî belgelerdeki örnekler üzerinden anlatıyoruz. Temel LINQ sorgularını henüz okumadıysanız önce EF Core LINQ sorguları yazısına bakmanızı öneririz; ilişkili verileri navigation üzerinden yüklemek ise Include ve eager loading yazısının konusudur.

Karmaşık operatörler neden ayrı bir konu?

Karmaşık operatörler neden ayrı bir konu?

LINQ'te birden fazla veri kaynağını birleştiren ya da sonuçları yeniden şekillendiren operatörlerin hepsinin veritabanı tarafında karşılığı yoktur. Belgeler bu noktada iki önemli uyarı yapar. Birincisi, aynı sonucu veren iki farklı LINQ yazımından biri SQL'e çevrilirken diğeri çevrilemeyebilir. İkincisi, çeviri desteği sağlayıcıdan sağlayıcıya değişir: SQL Server sağlayıcısında sorunsuz çalışan bir sorgu SQLite üzerinde çevrilemeyebilir. Bu yüzden karmaşık bir sorgu yazdığınızda yalnızca derlenmesine değil, üretilen SQL'e de bakmanız gerekir. Üretilen SQL'i görmenin yolları EF Core SQL loglama yazısında anlatılıyor.

Çevrilemeyen bir ifade sorgunun son Select adımı dışında bir yerdeyse EF Core çalışma zamanında hata fırlatır; bu davranışın ayrıntıları ve çözüm yolları client evaluation hatası yazısındadır. Aşağıdaki bölümlerde her operatör için belgelerin desteklenen biçim olarak gösterdiği kalıpları sırayla inceliyoruz. SQL çıktıları belgelerdeki SQL Server örnek çıktılarıdır; sizin sağlayıcınızda tablo ve kolon adları ya da sözdizimi farklı görünebilir.

Join: anahtar eşleşmesiyle INNER JOIN

LINQ Join operatörü iki kaynağı, her kaynak için verdiğiniz anahtar seçicilere göre bağlar ve anahtarlar eşleştiğinde bir değer çifti üretir. İlişkisel veritabanlarında bunun doğal karşılığı INNER JOIN ifadesidir. LINQ tarafında dış ve iç olmak üzere iki ayrı anahtar seçici bulunur, veritabanı ise tek bir birleştirme koşulu ister; EF Core bu farkı dış anahtarın iç anahtara eşit olması koşulunu üreterek kapatır.

csharp
var query = from photo in context.Set<PersonPhoto>()
            join person in context.Set<Person>()
                on photo.PersonPhotoId equals person.PhotoId
            select new { person, photo };

Belgelerde bu sorgu için gösterilen örnek SQL çıktısı şöyledir:

sql
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]

Anahtar seçiciler anonim tip olduğunda EF Core karşılaştırmayı bileşen bileşen yapar ve her alan için ayrı bir eşitlik koşulu üretip bunları AND ile bağlar. Böylece birden fazla kolona dayalı birleştirme yazabilirsiniz. Burada dikkat edilmesi gereken nokta tiplerin uyumudur: belgelerdeki örnekte bir taraf int, diğer taraf int? olduğu için dış tarafta (int?)photo.PersonPhotoId şeklinde bir dönüştürme yapılmıştır. Anonim tiplerin eşit sayılabilmesi için alan adlarının ve tiplerinin iki tarafta aynı olması gerekir.

csharp
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 };

Belgelerin örnek çıktısında birleştirme koşulu ON ([p0].[PersonPhotoId] = [p].[PhotoId] AND ([p0].[Caption] = N'SN')) biçiminde iki parçalı olarak görünür. Pratikte modelinizde bir ilişki ve navigation tanımlıysa çoğu zaman elle Join yazmanıza gerek kalmaz; navigation üzerinden erişim de EF Core tarafından birleştirmeye çevrilir. Elle Join, modelde ilişki olarak tanımlanmamış iki kaynağı bağlamanız gerektiğinde işe yarar. İlişki kavramları için EF Core ilişkiler ve navigation yazısına bakabilirsiniz.

GroupJoin neden çoğu durumda çevrilmez?

GroupJoin operatörü Join gibi iki kaynağı bağlar, ancak her dış öğe için eşleşen iç öğelerden oluşan bir grup üretir. Örneğin bir Blog ile ona ait IEnumerable<Post> koleksiyonunu tek bir sonuçta döndürmek istediğinizde akla gelen operatör budur. Sorun şudur: ilişkisel veritabanlarında istemci tarafındaki bir nesne koleksiyonunu temsil edecek bir yapı yoktur. Özel bir seçici olmadan bu grubu oluşturmak tüm veriyi sunucudan çekmeyi gerektirir; seçici veriyi daraltıyorsa da tüm veriyi çekmek performans sorununa yol açar. Belgeler bu yüzden EF Core'un GroupJoin çevirmediğini açıkça söyler.

csharp
var query = from b in context.Set<Blog>()
            join p in context.Set<Post>()
                on b.BlogId equals p.BlogId into grouping
            select new { b, grouping };

Bu kalıbı bir blogu ve yazılarını birlikte almak için kullanmak istiyorsanız doğru araç navigation ve Include ya da navigation üzerinden projeksiyondur. GroupJoin yine de bir yerde gereklidir: sol birleştirmenin eski yazımında, hemen ardından SelectMany ve DefaultIfEmpty ile düzleştirildiğinde. Bu kalıbı aşağıda ayrıca ele alıyoruz.

SelectMany: CROSS JOIN, INNER JOIN, LEFT JOIN ve APPLY

SelectMany: CROSS JOIN, INNER JOIN, LEFT JOIN ve APPLY: Seçici dış kaynağa hiç başvurmuyorsa, Seçici dış kaynağa bir Where içinde başvuruyorsa, Seçici dış kaynağa Where dışında...

SelectMany her dış öğe için bir koleksiyon seçicisini dolaşır ve iki kaynaktan değer çiftleri üretir. Bir anlamda koşulsuz bir birleştirmedir. Sunucuda neye çevrileceği, koleksiyon seçicinin dış kaynağa nasıl bağlı olduğuna göre değişir. Belgeler üç durum ayırır ve bu ayrımı bilmek, ürettiğiniz SQL'i önceden tahmin etmenizi sağlar.

Seçici dış kaynağa hiç başvurmuyorsa

Koleksiyon seçici dış öğeden hiçbir şey kullanmıyorsa sonuç iki kaynağın kartezyen çarpımıdır ve ilişkisel veritabanlarında CROSS JOIN olarak çevrilir. Her blog her yazıyla eşleşir; tablolar büyüdükçe satır sayısı çarpımla arttığı için bunu bilinçli olarak kullanmadığınız sürece kaçınmanız gereken bir biçimdir.

csharp
var query = from b in context.Set<Blog>()
            from p in context.Set<Post>()
            select new { b, p };

Seçici dış kaynağa bir Where içinde başvuruyorsa

Koleksiyon seçicide dış öğeye başvuran bir Where varsa EF Core bunu veritabanı birleştirmesine çevirir ve bu koşulu birleştirme koşulu olarak kullanır. Belgelere göre bu durum genellikle dış öğenin koleksiyon navigation'ını seçici olarak kullandığınızda ortaya çıkar. Koleksiyon bir dış öğe için boşsa o öğe sonuçta hiç görünmez; seçiciye DefaultIfEmpty eklerseniz dış öğe, iç öğenin varsayılan değeriyle (referans tipler için null) eşleşir. Sonuç olarak DefaultIfEmpty yokken INNER JOIN, varken LEFT JOIN üretilir.

csharp
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 };

Belgelerin örnek çıktısında ilk sorgu INNER JOIN [Posts] AS [p] ON [b].[BlogId] = [p].[BlogId], ikinci sorgu ise aynı koşulla LEFT JOIN üretir. Bu kalıp, sol birleştirmeyi GroupJoin kullanmadan yazmanın da bir yoludur.

Seçici dış kaynağa Where dışında başvuruyorsa

Koleksiyon seçici dış öğeye bir Where koşulu dışında başvuruyorsa, örneğin projeksiyonda dış öğenin bir alanını kullanıyorsa, bu bir veritabanı birleştirmesine çevrilemez; seçicinin her dış öğe için ayrı değerlendirilmesi gerekir. Pek çok ilişkisel veritabanında bunun karşılığı APPLY işlemleridir: DefaultIfEmpty yokken CROSS APPLY, varken OUTER APPLY. Belgeler burada önemli bir sınır koyar: SQLite gibi bazı veritabanları APPLY desteklemez, bu yüzden bu tür sorgular orada çevrilemeyebilir.

csharp
var query = from b in context.Set<Blog>()
            from p in context.Set<Post>().Select(p => b.Url + "=>" + p.Title)
            select new { b, p };

Geliştirmeyi SQLite ile yapıp üretimde SQL Server kullanıyorsanız (ya da tersi) bu ayrım özellikle önemlidir: bir ortamda çalışan sorgu diğerinde çevrilemeyebilir. Testlerinizi mümkünse üretimdeki sağlayıcıyla çalıştırmak bu tür sürprizleri erken yakalar; bu konu EF Core test yazma yazısında ele alınıyor.

GroupBy: GROUP BY ve HAVING çevirisi

LINQ GroupBy operatörü IGrouping<TKey, TElement> türünde sonuçlar üretir; IGrouping aynı zamanda bir IEnumerable<TElement> olduğu için gruplamanın ardından istediğiniz LINQ operatörünü kullanabilirsiniz. Ancak hiçbir veritabanı yapısı bir IGrouping nesnesini temsil edemez. Belgelere göre bu yüzden GroupBy çoğu durumda doğrudan çevrilemez; çevrilebilen kalıp, her gruba skaler değer döndüren bir toplama (aggregate) operatörü uyguladığınız durumdur.

SQL'deki GROUP BY da kısıtlayıcıdır: yalnızca skaler değerlere göre gruplayabilirsiniz ve projeksiyonda yalnızca gruplama anahtarı kolonları ile kolonlar üzerinde uygulanmış toplama fonksiyonları yer alabilir. EF Core bu kalıbı tanır ve sunucuya çevirir:

csharp
var query = from p in context.Set<Post>()
            group p by p.AuthorId
            into g
            select new { g.Key, Count = g.Count() };

Belgelerin örnek SQL çıktısı:

sql
SELECT [p].[AuthorId] AS [Key], COUNT(*) AS [Count]
FROM [Posts] AS [p]
GROUP BY [p].[AuthorId]

Toplama operatörü gruplamadan sonra bir Where içinde kullanıldığında EF Core bunu SQL'de HAVING ifadesine çevirir; OrderBy gibi sıralama operatörlerinde de toplama değerleri kullanılabilir. GroupBy öncesindeki sorgu parçası, sunucuya çevrilebildiği sürece istediğiniz kadar karmaşık olabilir. Toplama operatörleriyle grupları ortadan kaldırdıktan sonra sonucun üzerine diğer sorgular gibi yeni operatörler ekleyebilirsiniz.

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

Belgelerdeki örnek çıktıda bu sorgu GROUP BY [p].[AuthorId] satırının ardından HAVING COUNT(*) > 0 ve ORDER BY [p].[AuthorId] üretir.

Desteklenen toplama fonksiyonları

Belgelerde EF Core'un desteklediği standart LINQ toplama operatörleri ve SQL karşılıkları şöyle listelenir. Sağlayıcılar bunlara ek fonksiyonlar sunabilir; örneğin SQL Server sağlayıcısının eşleme tablosunda LongCount() için COUNT_BIG(*) ve string.Join için STRING_AGG karşılığı yer alır.

.NETSQL
Average(x => x.Property)AVG(Property)
Count()COUNT(*)
LongCount()COUNT(*)
Max(x => x.Property)MAX(Property)
Min(x => x.Property)MIN(Property)
Sum(x => x.Property)SUM(Property)

Bazı toplama fonksiyonlarında girdinin kendisi de şekillendirilebilir: sağlayıcıya bağlı olarak Where girdiyi süzebilir, OrderBy sırasını belirleyebilir, Distinct tekrarları kaldırabilir. Aşağıdaki sorgu belgelerdeki bu biçimleri bir arada gösterir:

csharp
var query = context.Posts
    .GroupBy(p => p.AuthorId)
    .Select(g => new
    {
        g.Key,
        Count = g.Count(),
        DistinctBlogCount = g.Select(p => p.BlogId).Distinct().Count(),
        OrderedTitles = string.Join(
            "|",
            g.OrderBy(p => p.Title).Select(p => p.Title)),
        FilteredTitles = string.Join(
            "|",
            g.Where(p => p.Rating >= 4).Select(p => p.Title))
    });

Hangi biçimlerin çevrildiği sağlayıcıya göre değişir. Örneğin SQL Server eşleme tablosunda sıralı STRING_AGG ... WITHIN GROUP (ORDER BY ...) çevirisinin "EF Core 11.0" ile eklendiği yazar; EF Core 11 şu an geliştirme aşamasında olduğu için EF Core 10 kullanıyorsanız sıralı birleştirme gibi biçimlere güvenmeden önce sağlayıcınızın fonksiyon eşleme sayfasına bakın.

Standart toplama operatörlerinin IQueryable aşırı yüklemeleri vardır ve doğrudan bütün sorguya uygulanabilir. Sağlayıcıya özgü bazı toplama fonksiyonları ise yalnızca IEnumerable aşırı yüklemesi sunduğu için yalnızca bir gruplama içinde kullanılabilir. Böyle bir fonksiyonu bütün sorguya uygulamak için belgelerin önerdiği yöntem sabit bir değere göre gruplamaktır:

csharp
var standardDeviation = context.Posts
    .GroupBy(_ => 1)
    .Select(g => EF.Functions.StandardDeviationSample(g.Select(p => p.Rating)))
    .FirstOrDefault();

Sabit değer tüm sonuçlar için tek bir grup oluşturur. Kaynakta hiç satır yoksa grup da oluşmaz ve FirstOrDefault varsayılan değeri döndürür. Belgeler ayrıca EF Core'un şu an kullanıcı tanımlı toplama fonksiyonlarını eşlemeyi desteklemediğini not eder.

Toplamasız GroupBy: gruplar istemcide oluşturulur

Bir IGrouping veritabanında temsil edilemese de belgelere göre EF Core 7.0 ve sonrası bazı durumlarda grupları sonuçlar veritabanından geldikten sonra oluşturabilir. Bu, ilişkili koleksiyonları Include ile yüklemenin işleyişine benzer. Örneğin context.Books.GroupBy(s => s.Price) sorgusu SQL'de GROUP BY üretmez; belgelerdeki örnek çıktıda kitapların fiyat, kimlik ve yazar kolonlarını ORDER BY [b].[Price] ile sıralı olarak çeken düz bir SELECT görünür ve gruplar istemcide oluşturulur. Bunun anlamı, bütün satırların uygulamaya taşınmasıdır; büyük tablolarda sayım veya toplam gibi bir değer istiyorsanız toplama operatörlü biçimi tercih edin.

Sol birleştirme: eski kalıp ve EF Core 10 ile LeftJoin

Sol birleştirme bir LINQ operatörü değildi, ancak ilişkisel veritabanlarında çok sık kullanılır. EF Core belirli bir LINQ kalıbını tanıyarak sunucuda LEFT JOIN üretir. Kalıp şudur: iki kaynak arasında bir GroupJoin kurulur, ardından grup SelectMany ile ve iç tarafta eşleşme yoksa null dönmesi için DefaultIfEmpty ile düzleştirilir.

csharp
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 };

Belgelerin örnek çıktısında bu sorgu LEFT JOIN [Posts] AS [p] ON [b].[BlogId] = [p].[BlogId] üretir. Bu kalıp ifade ağacında karmaşık bir yapı oluşturur. Bu yüzden EF Core, GroupJoin sonucunun hemen bir sonraki adımda düzleştirilmesini ister. GroupJoin, DefaultIfEmpty ve SelectMany kullansanız bile farklı bir düzende yazarsanız EF Core bunu sol birleştirme olarak tanımayabilir.

.NET 10 ile LINQ'e birinci sınıf bir LeftJoin metodu eklendi ve EF Core 10 bu metodu tanır. Artık aynı işi çok daha okunaklı yazabilirsiniz:

csharp
var query = context.Students
    .LeftJoin(
        context.Departments,
        student => student.DepartmentID,
        department => department.ID,
        (student, department) => new
        {
            student.FirstName,
            student.LastName,
            Department = department.Name ?? "[NONE]"
        });

Metodun dört parametresi vardır: iç kaynak, dış anahtar seçici, iç anahtar seçici ve sonuç seçici. Sonuç seçicide iç taraf eşleşme olmadığında null gelebileceği için örnekte ?? ile bir yedek değer verilmiştir. EF Core 10 benzer şekilde RightJoin operatörünü de destekler ve bunu veritabanında RIGHT JOIN olarak çevirir: ikinci koleksiyondaki tüm veriler korunur, birinciden yalnızca eşleşenler gelir. Belgelere göre C# sorgu sözdizimi (from x select x.Id biçimi) henüz sol veya sağ birleştirmeyi bu şekilde ifade etmeyi desteklemez; LeftJoin ve RightJoin yöntem sözdizimiyle yazılır.

Operatörlerin çevirisi bir bakışta

Operatörlerin çevirisi bir bakışta: Join (eşit anahtarlar), GroupJoin tek başına, SelectMany, seçici dışa bağlı değil, SelectMany, Where ile dışa bağlı
LINQ kalıbıTipik SQL karşılığıNot
Join (eşit anahtarlar)INNER JOINAnonim tipte bileşen bileşen eşitlik
GroupJoin tek başınaÇevrilmezNavigation ve Include tercih edin
SelectMany, seçici dışa bağlı değilCROSS JOINKartezyen çarpım
SelectMany, Where ile dışa bağlıINNER JOIN veya LEFT JOINDefaultIfEmpty varsa LEFT JOIN
SelectMany, Where dışında dışa bağlıCROSS APPLY veya OUTER APPLYSQLite APPLY desteklemez
GroupBy ve toplamaGROUP BY, HAVINGProjeksiyonda anahtar ve toplamalar
GroupBy, toplama yokSıralı SELECTGruplar istemcide (EF Core 7.0 ve sonrası)
GroupJoin, SelectMany, DefaultIfEmptyLEFT JOINDüzleştirme hemen ardından gelmeli
LeftJoin / RightJoinLEFT JOIN / RIGHT JOINEF Core 10 ve .NET 10

Küçük bir senaryo: yazarlara göre yazı sayısı ve yazısız bloglar

Bir blog platformunda iki rapor istediğinizi düşünün. Birincisi her yazarın kaç yazısı olduğu, ikincisi ise hiç yazısı olmayanlar dahil bütün blogların listesi. İlk rapor için belgelerdeki GroupBy kalıbı yeterlidir: AuthorId değerine göre gruplayıp Count() alırsınız. Bu sorgu sunucuda tek bir GROUP BY sorgusu olarak çalışır ve uygulamaya yazar başına yalnızca bir satır gelir. Yalnızca en az bir yazısı olan yazarları istiyorsanız gruplamadan sonra where g.Count() > 0 ekleyebilirsiniz; bu da HAVING olarak çevrilir.

İkinci rapor bir sol birleştirmedir. EF Core 10 kullanıyorsanız context.Blogs.LeftJoin(context.Posts, b => b.BlogId, p => p.BlogId, (b, p) => new { b.Url, Title = p.Title }) biçiminde yazabilirsiniz. Yazısı olmayan bloglar için iç taraf null olacağından projeksiyonda bu durumu düşünmeniz gerekir. Daha eski bir sürümle çalışan bir kod tabanında aynı sonucu join ... into grouping ve from p in grouping.DefaultIfEmpty() kalıbıyla alırsınız. Her iki durumda da sonucu yalnızca ihtiyacınız olan kolonlara indirgemek, ağ üzerinden taşınan veriyi azaltır; bu ilke EF Core performans optimizasyonu yazısında ayrıntılı anlatılıyor.

Bu iki raporu tek bir sorguda birleştirmeye çalışmak yerine ayrı sorgular olarak tutmak çoğu zaman daha okunaklıdır. Raporu bir sayfada gösterecekseniz sonuç sayısını sınırlamayı ve sayfalamayı da düşünün: büyük tablolarda Skip ve Take ile keyset yaklaşımının farkları EF Core sayfalama yazısında anlatılıyor.

Sık yapılan hatalar

  • GroupJoin sonucunu doğrudan döndürmek: Grubu düzleştirmeden projeksiyonda kullanmak çevrilmez. Blog ve yazıları birlikte istiyorsanız navigation ile Include ya da projeksiyon kullanın.
  • Sol birleştirme kalıbını bozmak: GroupJoin ile SelectMany arasına başka bir operatör koymak EF Core'un kalıbı tanımasını engelleyebilir. EF Core 10 kullanıyorsanız doğrudan LeftJoin yazın.
  • GroupBy sonrası tüm grubu projeksiyona koymak: SQL GROUP BY projeksiyonda yalnızca anahtar ve toplama değerleri taşıyabilir. Grubun öğelerini döndürmek istemci tarafında gruplama demektir ve bütün satırları uygulamaya taşır.
  • Sağlayıcı farkını unutmak: CROSS APPLY veya OUTER APPLY gerektiren sorgular SQLite üzerinde çevrilemeyebilir; sağlayıcıya özgü toplama fonksiyonları da başka sağlayıcılarda çalışmaz.
  • Navigation varken elle Join yazmak: Modelde tanımlı bir ilişki için navigation kullanmak hem daha kısa hem daha az hata yapmaya açıktır; elle Join ilişkisi tanımlı olmayan kaynaklar için uygundur.
  • Üretilen SQL'e bakmamak: Karmaşık sorguların çevirisi yazım biçimine duyarlıdır. Sorguyu yazdıktan sonra loglardan SQL'i kontrol etmek, sorunları üretime çıkmadan yakalamanın en kolay yoludur.

Sık Sorulan Sorular

EF Core'da left join nasıl yazılır?

EF Core 10 ve .NET 10 ile LeftJoin metodunu yöntem sözdizimiyle kullanabilirsiniz; EF Core bunu LEFT JOIN olarak çevirir. Önceki sürümlerde join ... into grouping ardından hemen from p in grouping.DefaultIfEmpty() kalıbı kullanılır. Bir koleksiyon seçicide dış öğeye Where ile başvurup DefaultIfEmpty eklemek de LEFT JOIN üretir.

GroupBy neden bazen istemcide çalışıyor?

Gruplamaya bir toplama operatörü uygulamadığınızda veritabanında karşılık gelen bir yapı yoktur. Belgelere göre EF Core 7.0 ve sonrası bu durumda sıralı bir SELECT çalıştırıp grupları sonuçlar geldikten sonra oluşturabilir. Sayım veya toplam gibi bir değer istiyorsanız toplama operatörlü biçimi kullanın ki iş veritabanında yapılsın.

RightJoin de destekleniyor mu?

Evet. EF Core 10 RightJoin operatörünü de destekler ve bunu RIGHT JOIN olarak çevirir. İkinci koleksiyondaki bütün veriler korunur, birinci koleksiyondan yalnızca eşleşen veriler gelir. C# sorgu sözdizimi henüz bu operatörleri ifade etmeyi desteklemez.

Join yerine navigation kullanmak daha mı iyi?

Modelde ilişki tanımlıysa çoğu durumda evet. Navigation üzerinden yazdığınız sorgular da EF Core tarafından birleştirmeye çevrilir ve kodunuz anahtar eşleşmesini tekrar tekrar yazmak zorunda kalmaz. İlişkili verilerin yüklenmesi için Include, çok sayıda koleksiyon yüklerken oluşan veri tekrarı için split query yazılarına bakabilirsiniz.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: EF Core öğrenme rehberi · EF Core LINQ sorguları · Include ve eager loading · Client evaluation hatası · EF Core performans