Varlık çerçevesi bağlantı sorgusu Include () birden çok alt öğe


176

Bu gerçekten elementli bir soru olabilir, ancak ÜÇ seviyeye (veya daha fazlasına) yayılan bir sorgu yazarken birden fazla çocuk varlığı eklemenin güzel bir yolu nedir?

yani ben 4 tablolar: Company, Employee, Employee_CarveEmployee_Country

Şirketin Çalışan ile 1: m ilişkisi vardır.

Çalışanın hem Employee_Car hem de Employee_Country ile 1: m ilişkisi vardır.

Tüm 4 tablodan veri döndüren bir sorgu yazmak istiyorsanız, şu anda yazıyorum:

Company company = context.Companies
                         .Include("Employee.Employee_Car")
                         .Include("Employee.Employee_Country")
                         .FirstOrDefault(c => c.Id == companyID);

Daha zarif bir yol olmalı! Bu uzun soluklu ve korkunç SQL üretir

VS 2010 ile EF4 kullanıyorum

Yanıtlar:


201

Uzantı yöntemlerini kullanın . NameOfContext öğesini nesne bağlamınızın adıyla değiştirin .

public static class Extensions{
   public static IQueryable<Company> CompleteCompanies(this NameOfContext context){
         return context.Companies
             .Include("Employee.Employee_Car")
             .Include("Employee.Employee_Country") ;
     }

     public static Company CompanyById(this NameOfContext context, int companyID){
         return context.Companies
             .Include("Employee.Employee_Car")
             .Include("Employee.Employee_Country")
             .FirstOrDefault(c => c.Id == companyID) ;
      }

}

Sonra kodunuz

     Company company = 
          context.CompleteCompanies().FirstOrDefault(c => c.Id == companyID);

     //or if you want even more
     Company company = 
          context.CompanyById(companyID);

Ama bunu şu şekilde kullanmak istiyorum: //inside public static class Extensions public static IQueryable<Company> CompleteCompanies(this DbSet<Company> table){ return table .Include("Employee.Employee_Car") .Include("Employee.Employee_Country") ; } //code will be... Company company = context.Companies.CompleteCompanies().FirstOrDefault(c => c.Id == companyID); //same for next advanced method
Hamid

Bullsye Nix. Uzantılar, önceden tanımlanmış işlevselliği genişletme ... iyi ... için ilk çağrı noktası olmalıdır.
16'da

12
Yıllar sonra, çalışma zamanı güvenli olmadıklarından, dize tabanlı içerir, tavsiye etmem. Navigation özelliğinin adı değişirse veya yanlış yazılırsa, kesilir. Bunun yerine yazılı dahil kullanmanızı öneririz.
Jeff Putz

2
nameof (class) 'ın kullanılmaya başlanmasından bu yana bu yaklaşımı güvenli bir şekilde kullanmak mümkündür. Varlık adı değişirse, derleme sırasında alınacaktır. Örnek: context.Companies.Include (nameof (Employee)) Aşağı inilmesi gerekiyorsa isimlerin (Employee) + "." + Nameof (Employee_Car)
Karl

Uzantı yöntemi tekniği burada onaylanan derlenmiş sorgular için çalışmaz (en azından EFCore'da değil): github.com/aspnet/EntityFrameworkCore/issues/7016
Dunge

156

EF 4.1 - EF 6

Uygun derinliğe Select ifadeleri sağlayarak gerekli istekli yükleme derinliğinin belirlenmesini sağlayan güçlü.Include bir tür vardır :

using System.Data.Entity; // NB!

var company = context.Companies
                     .Include(co => co.Employees.Select(emp => emp.Employee_Car))
                     .Include(co => co.Employees.Select(emp => emp.Employee_Country))
                     .FirstOrDefault(co => co.companyID == companyID);

Her iki durumda da üretilen Sql hala hiçbir şekilde sezgisel değildir, ancak yeterince performans sergilemektedir. Burada GitHub'a küçük bir örnek verdim

EF Çekirdek

.ThenInclude()Sözdizimi biraz farklı olmasına rağmen, EF Core'un yeni bir genişletme yöntemi vardır :

var company = context.Companies
                     .Include(co => co.Employees)
                           .ThenInclude(emp => emp.Employee_Car)
                      ...

Dokümanlara göre, .ThenIncludeakıl sağlığınızı korumak için ekstra 'girintiyi' içeride tutardım.

Eski Bilgiler (Bunu yapma):

Birden torun yükleme olabilir tek adımda yapılabilir, ancak bu sonraki düğümü aşağı gitmeden önce grafiğin yukarı oldukça garip ters sırtını gerektirir (Not: Bu çalışmaz AsNoTracking()- Bir çalışma zamanı hatası alırsınız):

var company = context.Companies
         .Include(co => 
             co.Employees
                .Select(emp => emp.Employee_Car
                    .Select(ec => ec.Employee)
                    .Select(emp2 => emp2.Employee_Country)))
         .FirstOrDefault(co => co.companyID == companyID);

Bu yüzden ilk seçenek (bir yaprak varlık derinliği modeli başına bir dahil) ile kalmak istiyorum.


4
Ben güçlü bir şekilde yazılmış .Include ifadeleri ile nasıl yapacağımı merak ediyordum. Select ile çocukları projelendirmek cevaptı!

1
"Co.Employees.Select (...)" terimim "" Çalışanlar "ın" Seç "[veya uzantı yöntemi] için bir tanım içermediğini söyleyen bir sözdizimi hatası gösteriyor. System.Data.Entity'yi dahil ettim. Birleştirilen tablodan yalnızca tek bir sütun almak istiyorum.
Chris Walsh

1
Aynı alt tabloya iki kez atıfta bulunan bir üst tablo vardı. Eski dizge sözdizimi ile doğru ilişkiyi önceden yüklemek zordu. Bu şekilde çok daha spesifik. Lütfen System.Data.Entity adının güçlü yazıldığından emin olun.
Karl

1
Net Core 2.1 ile System.Data.Entity yerine Microsoft.EntityFrameworkCore ad alanına ihtiyacım vardı
denvercoder9 4:18

27

Codeplex.com adresinde bu ilgilendiğiniz makaleyi bulabilirsiniz .

Makale, bildirim grafik şekilleri şeklinde birden çok tabloya yayılan sorguları ifade etmenin yeni bir yolunu sunar.

Ayrıca makale, bu yeni yaklaşımın EF sorguları ile kapsamlı bir performans karşılaştırması içermektedir. Bu analiz GBQ'nun EF sorgularından hızlı bir şekilde daha iyi performans gösterdiğini göstermektedir.


bu gerçek dünyadaki bir uygulamada nasıl uygulanabilir?
Victor.Uduak

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.