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

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

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)}")  

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

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 .


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.


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 :)


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")

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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.