積極式載入相關資料

積極式載入

您可以使用 Include 方法來指定要包含於查詢結果中的相關資料。 在下列範例中,於結果中所傳回部落格的 Posts 屬性將會填入相關文章。

using (var context = new BloggingContext())
{
    var blogs = context.Blogs
        .Include(blog => blog.Posts)
        .ToList();
}

提示

Entity Framework Core 會將導覽屬性自動修正為先前已載入至內容執行個體的任何其他實體。 因此,即使未明確包含導覽屬性的資料,如果先前已載入部分或所有相關的實體,則仍然可能會填入該屬性。

您可以將來自多個關聯性的相關資料包含至單一查詢。

using (var context = new BloggingContext())
{
    var blogs = context.Blogs
        .Include(blog => blog.Posts)
        .Include(blog => blog.Owner)
        .ToList();
}

警告

急切式載入單一查詢中的集合導覽可能會導致效能問題。 如需詳細資訊,請參閱 單一與分割查詢

包括多個層級

您可以使用 ThenInclude 方法,透過關聯性向下切入以包含多個層級的相關資料。 下列範例會載入所有部落格、其相關文章,以及每篇文章的作者。

using (var context = new BloggingContext())
{
    var blogs = context.Blogs
        .Include(blog => blog.Posts)
        .ThenInclude(post => post.Author)
        .ToList();
}

您可以將多個呼叫鏈結到 ThenInclude,以繼續包含更深層級的相關資料。

using (var context = new BloggingContext())
{
    var blogs = context.Blogs
        .Include(blog => blog.Posts)
        .ThenInclude(post => post.Author)
        .ThenInclude(author => author.Photo)
        .ToList();
}

您可以結合所有呼叫,以在相同的查詢中包含來自多個層級和多個根目錄的相關資料。

using (var context = new BloggingContext())
{
    var blogs = context.Blogs
        .Include(blog => blog.Posts)
        .ThenInclude(post => post.Author)
        .ThenInclude(author => author.Photo)
        .Include(blog => blog.Owner)
        .ThenInclude(owner => owner.Photo)
        .ToList();
}

您可能會想要針對所包括的其中一個實體包含多個相關實體。 例如,查詢 Blogs 時,您包括了 Posts,接著想要同時包含 PostsAuthorTags。 若要包含這兩者,您必須指定從根目錄開始的每個 Include 路徑。 例如,Blog -> Posts -> AuthorBlog -> Posts -> Tags。 這並不表示您將取得多餘的聯結;在大部分情況下,EF 會在產生 SQL 時合併聯結。

using (var context = new BloggingContext())
{
    var blogs = context.Blogs
        .Include(blog => blog.Posts)
        .ThenInclude(post => post.Author)
        .Include(blog => blog.Posts)
        .ThenInclude(post => post.Tags)
        .ToList();
}

提示

您也可以使用單 Include 一方法載入多個導覽。 這可用於所有參考的導覽「鏈結」,或當它們以單一集合結尾時。

using (var context = new BloggingContext())
{
    var blogs = context.Blogs
        .Include(blog => blog.Owner.AuthoredPosts)
        .ThenInclude(post => post.Blog.Owner.Photo)
        .ToList();
}

篩選的 include

套用 Include 以載入相關資料時,您可以將特定可列舉的作業新增至包含的集合導覽,以便篩選和排序結果。

支援的作業包括: Where 、、 OrderByOrderByDescendingThenByThenByDescendingSkip 、 和 Take

這類作業應該套用至傳遞至 Include 方法之 Lambda 中的集合導覽,如下列範例所示:

using (var context = new BloggingContext())
{
    var filteredBlogs = context.Blogs
        .Include(
            blog => blog.Posts
                .Where(post => post.BlogId == 1)
                .OrderByDescending(post => post.Title)
                .Take(5))
        .ToList();
}

每個包含的導覽只允許一組唯一的篩選作業。 如果針對指定的集合導覽套用多個 Include 作業( blog.Posts 在下列範例中),篩選作業只能在其中一個上指定:

using (var context = new BloggingContext())
{
    var filteredBlogs = context.Blogs
        .Include(blog => blog.Posts.Where(post => post.BlogId == 1))
        .ThenInclude(post => post.Author)
        .Include(blog => blog.Posts)
        .ThenInclude(post => post.Tags.OrderBy(postTag => postTag.TagId).Skip(3))
        .ToList();
}

相反地,可以針對包含多次的每個導覽套用相同的作業:

using (var context = new BloggingContext())
{
    var filteredBlogs = context.Blogs
        .Include(blog => blog.Posts.Where(post => post.BlogId == 1))
        .ThenInclude(post => post.Author)
        .Include(blog => blog.Posts.Where(post => post.BlogId == 1))
        .ThenInclude(post => post.Tags.OrderBy(postTag => postTag.TagId).Skip(3))
        .ToList();
}

警告

如果追蹤查詢,篩選 Include 的結果可能會因為 流覽修正 而非預期。 已查詢先前且已儲存在變更追蹤器中的所有相關實體,都會出現在篩選 Include 查詢的結果中,即使它們不符合篩選的需求也一樣。 在那些情況下,請考慮使用 NoTracking 查詢或重新建立 DbCoNtext。

範例:

var orders = context.Orders.Where(o => o.Id > 1000).ToList();

// customer entities will have references to all orders where Id > 1000, rather than > 5000
var filtered = context.Customers.Include(c => c.Orders.Where(o => o.Id > 5000)).ToList();

注意

如果追蹤查詢,系統會將套用篩選包含的流覽視為要載入。 這表示 EF Core 不會嘗試使用 明確載入或 延遲載入 重新載入其值,即使某些元素可能仍然遺失。

衍生類型中的 Include

您可以使用 和 ThenInclude ,只包含衍生型 Include 別上定義的導覽相關資料。

假設有下列模型:

public class SchoolContext : DbContext
{
    public DbSet<Person> People { get; set; }
    public DbSet<School> Schools { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<School>().HasMany(s => s.Students).WithOne(s => s.School);
    }
}

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class Student : Person
{
    public School School { get; set; }
}

public class School
{
    public int Id { get; set; }
    public string Name { get; set; }

    public List<Student> Students { get; set; }
}

School所有人員學生都可以使用許多模式急切地載入所有人員的內容:

  • 使用轉換

    context.People.Include(person => ((Student)person).School).ToList()
    
  • Using as 運算子

    context.People.Include(person => (person as Student).School).ToList()
    
  • 使用 採用 型別參數的 多載 Includestring

    context.People.Include("School").ToList()
    

自動包含導覽的模型設定

您可以在模型中設定每次使用 AutoInclude 方法從資料庫載入實體時包含的導覽。 其效果與 Include 在結果中傳回實體類型之每個查詢中的導覽相同。 下列範例示範如何設定要自動包含的導覽。

modelBuilder.Entity<Theme>().Navigation(e => e.ColorScheme).AutoInclude();

在上述設定之後,執行如下的查詢將會載入 ColorScheme 結果中所有主題的導覽。

using (var context = new BloggingContext())
{
    var themes = context.Themes.ToList();
}

不論結果中傳回的實體為何,都會套用此組態。 這表示如果實體因為使用導覽而處於結果中,使用 Include 其他實體類型或自動包含組態,則會載入其所有自動包含的導覽。 相同的規則會延伸至設定為實體衍生類型上自動包含的導覽。

如果針對特定查詢,您不想透過導覽載入相關資料,該導覽設定在模型層級設定為自動包含,您可以在查詢中使用 IgnoreAutoIncludes 方法。 使用此方法將會停止載入使用者設定為自動包含的所有導覽。 執行如下的查詢會從資料庫帶回所有主題,但即使它已設定為自動包含導覽,也不會載入 ColorScheme

using (var context = new BloggingContext())
{
    var themes = context.Themes.IgnoreAutoIncludes().ToList();
}

注意

擁有類型的導覽也會設定為慣例自動包含,而且使用 IgnoreAutoIncludes API 不會阻止它們被包含。 它們仍會包含在查詢結果中。