EF LINQ ประกอบด้วยเอนทิตีหลายแบบและซ้อนกัน


155

ตกลงฉันมีหน่วยงานสามระดับที่มีลำดับชั้นต่อไปนี้: หลักสูตร -> โมดูล -> บท

นี่คือคำสั่ง EF LINQ ดั้งเดิม:

Course course = db.Courses
                .Include(i => i.Modules.Select(s => s.Chapters))
                .Single(x => x.Id == id); 

ตอนนี้ฉันต้องการรวมเอนทิตีอื่นที่เรียกว่าแล็บซึ่งเชื่อมโยงกับหลักสูตร

ฉันจะรวมเอนทิตี Lab ได้อย่างไร

ฉันลองสิ่งต่อไปนี้ แต่มันไม่ทำงาน:

Course course = db.Courses
                .Include(i => i.Modules.Select(s => s.Chapters) && i.Lab)
                .Single(x => x.Id == id); 

มีความคิดเห็นเกี่ยวกับการรวม Entity ที่ 2 หรือไม่

คำแนะนำหรือข้อมูลใด ๆ จะได้รับการชื่นชมอย่างมาก ขอบคุณ!


1
การเพิ่มรายการอื่น.Includeควรใช้งานได้เว้นแต่คุณจะหมายความว่าการรวมเพิ่มเติมนั้นเป็นหลานของหลักสูตร ดูตัวเลือก
von v.

ซ้ำ / เกี่ยวข้องที่เป็นไปได้ของstackoverflow.com/q/3356541
StuartLC

คำตอบ:


234

คุณลองเพิ่มอีกInclude:

Course course = db.Courses
                .Include(i => i.Modules.Select(s => s.Chapters))
                .Include(i => i.Lab)
                .Single(x => x.Id == id);

วิธีการแก้ปัญหาของคุณล้มเหลวเพราะIncludeไม่ต้องใช้ตัวดำเนินการบูลีน

Include(i => i.Modules.Select(s => s.Chapters) &&          i.Lab)
                           ^^^                  ^             ^ 
                          list           bool operator    other list

อัปเดต เพื่อเรียนรู้เพิ่มเติมดาวน์โหลดLinqPadและดูตัวอย่าง ฉันคิดว่ามันเป็นวิธีที่เร็วที่สุดในการทำความคุ้นเคยกับ Linq และ Lambda

เป็นการเริ่มต้น - ความแตกต่างระหว่างSelectและIncludeคือการเลือกให้คุณเป็นผู้ตัดสินใจว่าคุณต้องการส่งคืนอะไร รวมเป็นฟังก์ชั่นการโหลดกระตือรือร้นที่บอก Entity Framework ที่คุณต้องการให้รวมข้อมูลจากตารางอื่น ๆ

ไวยากรณ์รวมยังสามารถอยู่ในสตริง แบบนี้:

           db.Courses
            .Include("Module.Chapter")
            .Include("Lab")
            .Single(x => x.Id == id);

แต่ตัวอย่างในLinqPadอธิบายได้ดีกว่านี้


ขอบคุณมัน! ฉันจะเรียนรู้เพิ่มเติมเกี่ยวกับเรื่องนี้ได้ที่ไหน ฉันสนใจเป็นพิเศษในความแตกต่างระหว่างรวมและเลือก
AnimaSola

3
มีเพียงอันเดียวที่ใช้ได้กับฉัน: .Include("Module.Chapter"). ความคิดใดที่จะเป็นเช่นนั้น?
Jo Smo

5
@JoSmo คุณต้องนำเข้าเนมสเปซSystem.Data.Enityเพื่อเข้าถึงส่วนขยายวิธีการ ข้อมูลเพิ่มเติมได้ที่นี่
Jens Kloster

using System.Data.Entity;ทำมัน ขอบคุณ!
Jo Smo

1
upvoted สำหรับการกล่าวถึง linqpad ที่ยอดเยี่ยม, และเคล็ดลับการใช้ System.Data.Entity, ขอบคุณ Jens
Mike

38

ใน Entity Framework Core ( EF.core) คุณสามารถใช้.ThenIncludeเพื่อรวมระดับถัดไป

var blogs = context.Blogs
    .Include(blog => blog.Posts)
        .ThenInclude(post => post.Author)
    .ToList();

ข้อมูลเพิ่มเติม: https://docs.microsoft.com/en-us/ef/core/querying/related-data

หมายเหตุ: สมมติว่าคุณต้องการหลายThenInclude()บนblog.Postsเพียงแค่ทำซ้ำและทำอีกInclude(blog => blog.Posts)ThenInclude(post => post.Other)

var blogs = context.Blogs
    .Include(blog => blog.Posts)
        .ThenInclude(post => post.Author)
    .Include(blog => blog.Posts)
        .ThenInclude(post => post.Other)
 .ToList();

ใน EF.core ฉันดูเหมือนจะไม่สามารถทำ. รวม (i => i.Modules.Select (s => s.Chapters)) โดยเฉพาะอย่างยิ่ง. เลือกข้างในรวมถึง ทุกคนสามารถยืนยันหรือพูดคุยกับใคร?
ttugates

@ttugates คุณตั้งใจทำอะไรกับตัวเลือกนี้ ฉันคิดว่าสิ่งที่คุณต้องการทำคือสิ่งที่คุณทำกับThenIncludeEF core อาจสร้างคำถามด้วยแบบอย่างที่ดีเพื่อเราจะได้ตอบคำถาม
Nick N.

@ Nick N - Entity Framework Linq Query: วิธีการไหนใน Nav คุณสมบัติหลายและเลือกจาก 3 Nav ทรัพย์สิน เนื่องจากสิ่งที่ฉันเลือกไม่ใช่สิ่งที่ฉันกำลังจับคู่อยู่จึงไม่จำเป็นต้องรวมถึงดังนั้นจึงเป็นคำถามเกี่ยวกับการสัมผัส คำถามของฉันอาจ "แคบ" เกินไป แต่ขอขอบคุณสำหรับความช่วยเหลือ
ttugates

1
อา. จริงๆแล้ว .ThinInclude () ทำงานได้ ใช้เวลาตลอดไปเพื่อให้ IntelliSense แสดงตารางที่เกี่ยวข้อง
Chris J

23

Includeเป็นส่วนหนึ่งของอินเทอร์เฟซที่คล่องแคล่วดังนั้นคุณสามารถเขียนหลาย ๆIncludeคำสั่งต่อไปนี้ได้

 db.Courses.Include(i => i.Modules.Select(s => s.Chapters))
           .Include(i => i.Lab)
           .Single(x => x.Id == id); 

ขอบคุณมัน! คุณช่วยชี้ฉันไปที่ที่ฉันสามารถเรียนรู้เพิ่มเติมเกี่ยวกับเรื่องนี้? ขอบคุณ!
AnimaSola

1
คุณรู้หรือไม่ว่าไวยากรณ์คืออะไรถ้า Modules มีหลายตารางที่คุณต้องการเข้าร่วม บอกว่ามันเชื่อมโยงไปยังบทและอย่างอื่น?
David Spence

เป็นส่วนหนึ่งของ. Net อย่างคล่องแคล่วหรือเป็นไลบรารี่ที่จำเป็นต้องติดตั้งหรือไม่?
codea

19

คุณสามารถลอง

db.Courses.Include("Modules.Chapters").Single(c => c.Id == id);

4
ขอบคุณ - เครื่องหมายจุดในสตริงมีประโยชน์มาก
Evert

1
สิ่งนี้มีประโยชน์ แต่เหตุผลหนึ่งที่จะไม่ใช้สิ่งนี้คือความสะดวกในการปรับโครงสร้างใหม่ในภายหลัง: หากคุณเปลี่ยนชื่อเอนทิตี "บท" ในบางกรณีตัวอย่างอื่นจะถูกเปลี่ยนชื่อโดยอัตโนมัติ อีกประการหนึ่งคือข้อผิดพลาดจะพบได้เร็วขึ้น: ณ เวลารวบรวมไม่ใช่เวลาทำงาน
MGOwen

2

หนึ่งอาจเขียนวิธีการขยายเช่นนี้

    /// <summary>
    /// Includes an array of navigation properties for the specified query 
    /// </summary>
    /// <typeparam name="T">The type of the entity</typeparam>
    /// <param name="query">The query to include navigation properties for that</param>
    /// <param name="navProperties">The array of navigation properties to include</param>
    /// <returns></returns>
    public static IQueryable<T> Include<T>(this IQueryable<T> query, params string[] navProperties)
        where T : class
    {
        foreach (var navProperty in navProperties)
            query = query.Include(navProperty);

        return query;
    }

และใช้อย่างนี้แม้ในการนำไปใช้ทั่วไป:

string[] includedNavigationProperties = new string[] { "NavProp1.SubNavProp", "NavProp2" };

var query = context.Set<T>()
.Include(includedNavigationProperties);

ฉันลองคำตอบของคุณแล้ว แต่มันกำลังโยนสแต็คโอเวอร์โฟลว์เซสชั่นเนื่องจากการวนซ้ำไม่สิ้นสุดกับตัวเอง
วิคตอเรียเอส

1
@VictoriaS. คุณสามารถเปลี่ยนชื่อวิธีการขยายเพื่อไม่ให้ยุ่งกับของจริงInclude
Mohsen Afshin
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.