Kerangka Entitas - Sertakan Beberapa Level Properti

376

Metode Include () berfungsi cukup baik untuk Daftar pada objek. Tapi bagaimana jika saya harus pergi dua level? Misalnya, metode di bawah ini akan mengembalikan ApplicationServers dengan properti yang disertakan yang ditampilkan di sini. Namun, ApplicationsWithOverrideGroup adalah wadah lain yang menampung objek kompleks lainnya. Bisakah saya melakukan Include () di properti itu juga? Atau bagaimana saya bisa membuat properti itu dimuat sepenuhnya?

Seperti sekarang, metode ini:

public IEnumerable<ApplicationServer> GetAll()
{
    return this.Database.ApplicationServers
        .Include(x => x.ApplicationsWithOverrideGroup)                
        .Include(x => x.ApplicationWithGroupToForceInstallList)
        .Include(x => x.CustomVariableGroups)                
        .ToList();
}

Akan mengisi hanya properti yang Diaktifkan (di bawah) dan bukan properti Aplikasi atau CustomVariableGroup (di bawah). Bagaimana saya mewujudkan ini?

public class ApplicationWithOverrideVariableGroup : EntityBase
{
    public bool Enabled { get; set; }
    public Application Application { get; set; }
    public CustomVariableGroup CustomVariableGroup { get; set; }
}
Bob Horn
sumber
Hi, Mengapa saya mendapatkan pengecualian sebuah Expression must be a member expressionketika saya mencoba ini: Untuk menyertakan koleksi dan kemudian tingkat koleksi satu ke bawah: query.Include(e => e.Level1Collection.Select(l1 => l1.Level2Collection)).
Joe.wang
1
@ BobHorn, saya memiliki masalah yang sama .. Dalam kasus saya, sarang jauh di dalam beberapa lapisan, saya berhasil melakukan termasuk yang Anda tunjukkan. Dalam SQL yang dihasilkan, saya bisa melihat semua kolom kembali dengan nama alias yang berbeda sebagai c1, c2 sesuatu seperti itu. Pertanyaan saya adalah, bagaimana saya bisa membentuk koleksi DTO bersarang dari semua saya termasuk :( .. Mungkin Anda dapat mengambil contoh di atas sendiri, di mana kami mengembalikan semua kolom tanpa DTO kustom (yang itu sendiri adalah koleksi DTO )
TechQuery

Jawaban:

705

Untuk EF 6

using System.Data.Entity;

query.Include(x => x.Collection.Select(y => y.Property))

Pastikan Anda menambahkan using System.Data.Entity;untuk mendapatkan versi Includeyang menggunakan lambda.


Untuk EF Core

Gunakan metode baru ThenInclude

query.Include(x => x.Collection)
     .ThenInclude(x => x.Property);
Diego Torres
sumber
1
Saya tidak bisa melakukan Sertakan () di ApplicationsWithOverrideGroup. Itu tidak muncul di intellisense.
Bob Horn
Saya tidak dapat menggunakan hasil edit Anda karena ApplicationsWithOverrideGroup adalah Daftar. Aplikasi adalah properti pada setiap item dalam daftar, bukan pada daftar itu sendiri.
Bob Horn
1
Ahhhh, tapi tautan yang Anda berikan itu tampaknya memberikan jawabannya. Biarkan saya coba ini: Untuk memasukkan koleksi dan kemudian koleksi satu tingkat turun: query.Include (e => e.Level1Collection.Select (l1 => l1.Level2Collection)).
Bob Horn
60
Ingatlah untuk memasukkan System.Data.Entity dalam usings. Jika tidak, Intellisense hanya akan memberikan versi metode jalur Sertakan (string).
OJ Raqueño
5
@Adeem Anda perlu menelepon Includeuntuk setiap properti:Db.States.Include(state => state.Cities.Select(city => city.Customers).Include(state => state.Cities.Select(city => city.Vendors)
Diego Torres
72

Jika saya mengerti Anda dengan benar, Anda bertanya tentang menyertakan properti bersarang. Jika begitu :

.Include(x => x.ApplicationsWithOverrideGroup.NestedProp)

atau

.Include("ApplicationsWithOverrideGroup.NestedProp")  

atau

.Include($"{nameof(ApplicationsWithOverrideGroup)}.{nameof(NestedProp)}")  
Judo
sumber
6
Terima kasih, saya bisa mencobanya. Saya berharap dapat menjaga hal-hal yang diketik dengan kuat dan menghindari string literal. Tetapi jika itu yang harus dilakukan ...
Bob Horn
1
Anda sudah dekat. Saya mungkin tidak jelas bahwa ApplicationsWithOverrideGroup adalah daftar. Terima kasih telah membantu!
Bob Horn
@ Judo, saya memiliki masalah yang sama .. Dalam kasus saya, sarang bersarang jauh di dalam beberapa lapisan, saya berhasil melakukan menyertakan yang Anda tunjukkan. Dalam SQL yang dihasilkan, saya bisa melihat semua kolom kembali dengan nama alias yang berbeda sebagai c1, c2 sesuatu seperti itu. Pertanyaan saya adalah, bagaimana saya bisa membentuk koleksi DTO bersarang dari semua saya termasuk :( .. Mungkin Anda dapat mengambil contoh di atas sendiri, di mana kami mengembalikan semua kolom tanpa DTO kustom (yang itu sendiri adalah koleksi DTO )
TechQuery
2
Ingatlah untuk memasukkan System.Data.Entity dalam usings. Kalau tidak, Intellisense hanya akan memberi Anda Include(string path)versi metode ini.
AlexMelw
53

EF Core: Menggunakan "ThenInclude" untuk memuat level mutiple: Misalnya:

var blogs = context.Blogs
    .Include(blog => blog.Posts)
        .ThenInclude(post => post.Author)
        .ThenInclude(author => author.Photo)
    .ToList();
thangcao
sumber
53
Sepertinya ini hanya EF Core
Chris Marisic
27
FYI: VS2017 Intellisense tidak berfungsi untuk. Kemudian Sertakan. Cukup ketikkan menurut Anda bagaimana seharusnya dan penyorotan kesalahan harus hilang.
JohnWrensby
4
Saya ingin menekankan komentar @JohnWrensby, Intellisense kadang-kadang membutuhkan waktu lama untuk menangani ThenInclude ini, ini bisa sangat membingungkan bagi pengguna baru. Saya juga memiliki kasus di mana ekspresi Sertakan lambda sederhana tidak ditangani dengan benar, sampai Anda cukup ketik dan kompilasi, mengabaikan "kesalahan" yang ditunjukkan dalam VS.
Pac0
@ Pac0 Anda menyelamatkan hari saya. berjuang untuk melihat barang-barang anak dan tidak bisa.
Bendram
28

Saya membuat pembantu kecil untuk Entity Framework 6 (.Net Core style), untuk memasukkan sub-entitas dengan cara yang baik.

Itu ada di NuGet sekarang: Instal-Paket ThenInclude.EF6

using System.Data.Entity;

var thenInclude = context.One.Include(x => x.Twoes)
    .ThenInclude(x=> x.Threes)
    .ThenInclude(x=> x.Fours)
    .ThenInclude(x=> x.Fives)
    .ThenInclude(x => x.Sixes)
    .Include(x=> x.Other)
    .ToList();

Paket ini tersedia di GitHub .

Lenny32
sumber
hai, saya memiliki pengecualian pada saat runtime, tidak dapat menampilkan IncludableQueryable <observablecollection> ke IncludableQueryable <genericcollection>
user2475096
Saya menggunakan db terlebih dahulu dan saya telah memodifikasi file tt untuk mendapatkan ObservableCollections untuk semua entitas saya, setiap bantuan dipersilahkan.
user2475096
2
@ lenny32 sesuatu yang harus diperhatikan dengan ekstensi ini?
Aaron Hudon
Perhatikan bahwa ini tidak diperlukan jika properti tempat Anda bernavigasi adalah satu-ke-satu dengan DbSet tempat Anda bernavigasi, dan Anda dapat DbSet<One>().Include(x => x.Two.Three.Four.Five.Six)menggunakan satu-satunya kelemahan saat Anda sedang menghitung produk kartesius dan berpotensi meningkatkan bandwidth.
John Zabroski
23

Lebih banyak contoh EFCore di MSDN menunjukkan bahwa Anda dapat melakukan beberapa hal yang cukup rumit dengan Includedan ThenInclude.

Ini adalah contoh yang baik tentang seberapa kompleks Anda bisa mendapatkan (ini semua adalah satu pernyataan!):

viewModel.Instructors = await _context.Instructors

      .Include(i => i.OfficeAssignment)

      .Include(i => i.CourseAssignments)
        .ThenInclude(i => i.Course)
            .ThenInclude(i => i.Enrollments)
                .ThenInclude(i => i.Student)

      .Include(i => i.CourseAssignments)
        .ThenInclude(i => i.Course)
            .ThenInclude(i => i.Department)

      .AsNoTracking()
      .OrderBy(i => i.LastName)
      .ToListAsync();

Lihat bagaimana Anda dapat rantai Includebahkan setelah ThenIncludedan itu semacam 'me-reset' Anda kembali ke tingkat entitas tingkat atas (Instruktur).

Anda bahkan dapat mengulangi koleksi 'tingkat pertama' yang sama (Tugas Kursus) beberapa kali diikuti dengan ThenIncludesperintah terpisah untuk sampai ke entitas anak yang berbeda.

Perhatikan bahwa permintaan Anda yang sebenarnya harus ditandai pada akhir rantai Includeatau ThenIncludes. Berikut ini TIDAK berfungsi:

var query = _context.Instructors.AsQueryable();
query.Include(i => i.OfficeAssignment);

var first10Instructors = query.Take(10).ToArray();

Akan sangat menyarankan Anda mengatur pencatatan dan memastikan pertanyaan Anda tidak di luar kendali jika Anda memasukkan lebih dari satu atau dua hal. Sangat penting untuk melihat cara kerjanya - dan Anda akan melihat setiap 'sertakan' yang terpisah biasanya merupakan kueri baru untuk menghindari gabungan besar-besaran yang mengembalikan data yang berlebihan.

AsNoTracking dapat sangat mempercepat jika Anda tidak benar-benar mengedit entitas dan menyimpan ulang.

Simon_Weaver
sumber
Apakah ada cara untuk mendapatkan baik Pendaftaran dan Departemen tanpa berulang Anda. Termasuk untuk CourseAssignment dan Course? (Sejauh ini, sepertinya Api bisa masuk lebih dalam dengan. Kemudian Sertakan, atau kembali ke tingkat atas dengan. Sertakan, tetapi tidak ada yang tetap pada level yang sama?)
William Jockusch
Jika Anda ingin malas memuat, lihat terus untuk EF Core 2.1 blogs.msdn.microsoft.com/dotnet/2018/02/02/… tetapi jika Anda hanya ingin memuat lebih banyak di tingkat yang sama saya pikir ini adalah desain. Saya tidak yakin apa yang Anda pikirkan - tidak memerlukan banyak tambahan untuk melakukan ini dan itu sangat mengurangi apa yang kembali dari database. Entitas mungkin hanya memiliki satu atau dua hal 'level yang sama' tetapi entitas itu mungkin memiliki 50 untuk proyek besar, secara eksplisit membuat aplikasi Anda jauh lebih cepat.
Simon_Weaver
Ini adalah penjelasan yang bagus tentang konsep Sertakan "mengatur ulang" level kembali ke level awal lagi. Membantu saya membungkus kepala saya di sekitar hirarki sistem termasuk. Bersulang!
AFM-Horizon
22

Saya juga harus menggunakan banyak termasuk dan pada level 3 saya membutuhkan beberapa properti

(from e in context.JobCategorySet
                      where e.Id == id &&
                            e.AgencyId == agencyId
                      select e)
                      .Include(x => x.JobCategorySkillDetails)
                      .Include(x => x.Shifts.Select(r => r.Rate).Select(rt => rt.DurationType))
                      .Include(x => x.Shifts.Select(r => r.Rate).Select(rt => rt.RuleType))
                      .Include(x => x.Shifts.Select(r => r.Rate).Select(rt => rt.RateType))
                      .FirstOrDefaultAsync();

Ini dapat membantu seseorang :)

dnxit
sumber
1
dapatkah ini dilakukan tanpa mengulang.Include(x => x.Shifts.Select(r => r.Rate).Select(rt => rt......
Multinerd
baik itu tergantung, seberapa dalam Anda ingin pergi
dnxit
7

Biarkan saya menyatakan dengan jelas bahwa Anda dapat menggunakan string overload untuk memasukkan level bersarang terlepas dari banyaknya hubungan yang terkait, jika Anda tidak keberatan menggunakan string literal:

query.Include("Collection.Property")
mrmashal
sumber
1
Metode ini sangat membantu bagi saya untuk mengetahui bagaimana ini dapat dikodekan dalam VB, karena saya tidak dapat menemukan di mana pun setelah jam googling.
Coder
Ini sangat bagus untuk saya, saya sering menggunakan ini !!! Ia bahkan bekerja dikombinasikan dengan pernyataan .Pilih Banyak:query.SelectMany(x=>x.foos).Include("bar").Include("bar.docs")...
Ephie