関連データの読み込みLoading Related Data

Entity Framework Core では、関連エンティティの読み込みをモデルで、ナビゲーション プロパティを使用することができます。Entity Framework Core allows you to use the navigation properties in your model to load related entities. 関連するデータの読み込みに使用される 3 つの一般的な O/RM パターンがあります。There are three common O/RM patterns used to load related data.

  • 一括読み込み最初のクエリの一部として、データベースから、関連するデータが読み込まれたことを意味します。Eager loading means that the related data is loaded from the database as part of the initial query.
  • 明示的な読み込みは後で、データベースから、関連するデータを明示的に読み込むことを意味します。Explicit loading means that the related data is explicitly loaded from the database at a later time.
  • 遅延読み込みナビゲーション プロパティにアクセスする場合、関連するデータが透過的にデータベースから読み込むことを意味します。Lazy loading means that the related data is transparently loaded from the database when the navigation property is accessed. 遅延読み込みは、まだ EF Core では可能ではありません。Lazy loading is not yet possible with EF Core.

ヒント

この記事を表示するサンプルGitHub でします。You can view this article's sample on GitHub.

一括読み込みEager loading

使用することができます、Includeクエリの結果に含まれる関連データを指定します。You can use the Include method to specify related data to be included in query results. 次の例では、ブログの結果に返される必要があります、Postsプロパティとして、関連する投稿に設定されます。In the following example, the blogs that are returned in the results will have their Posts property populated with the related posts.

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

ヒント

Entity Framework Core は自動的に修正をするナビゲーション プロパティをコンテキストのインスタンスに以前に読み込まれたその他のエンティティです。Entity Framework Core will automatically fix-up navigation properties to any other entities that were previously loaded into the context instance. 場合でも、明示的には、ナビゲーション プロパティのデータを含まない、いくつかの場合は、プロパティを作成してか、以前に読み込まれたすべての関連するエンティティ。So even if you don't explicitly include the data for a navigation property, the property may still be populated if some or all of the related entities were previously loaded.

単一のクエリでは、複数のリレーションシップから関連するデータを含めることができます。You can include related data from multiple relationships in a single query.

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

複数のレベルを含むIncluding multiple levels

使用して関連するデータの複数のレベルを含むへのリレーションシップを通じてドリルダウンすることができます、ThenIncludeメソッドです。You can drill down thru relationships to include multiple levels of related data using the ThenInclude method. 次の例では、すべてのブログの関連する投稿を各投稿の作成者を読み込みます。The following example loads all blogs, their related posts, and the author of each post.

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

複数の呼び出しをチェーンするThenInclude関連データのレベルを含めてさらに続行します。You can chain multiple calls to ThenInclude to continue including further levels of related data.

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

これを同じクエリで複数のレベルと複数のルートから関連するデータを含めるにはすべてを組み合わせることができます。You can combine all of this to include related data from multiple levels and multiple roots in the same query.

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

いずれかが含まれるエンティティの複数の関連エンティティを追加することがあります。You may want to include multiple related entities for one of the entities that is being included. たとえば、クエリを実行するときにBlogが含まれています、Posts両方を格納して、AuthorTagsPostsです。For example, when querying Blogs, you include Posts and then want to include both the Author and Tags of the Posts. これを行うには、ルートからのパスを含めるそれぞれを指定する必要があります。To do this, you need to specify each include path starting at the root. たとえば、 Blog -> Posts -> AuthorBlog -> Posts -> TagsFor example, Blog -> Posts -> Author and Blog -> Posts -> Tags. 表示される冗長な結合、EF の統合はほとんどの場合、結合 SQL を生成するときにありません。This does not mean you will get redundant joins, in most cases EF will consolidate the joins when generating 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();
}

無視が含まれていますIgnored includes

不要になったクエリの開始とエンティティ型のインスタンスを返すように、クエリを変更する場合は、include 演算子は無視されます。If you change the query so that it no longer returns instances of the entity type that the query began with, then the include operators are ignored.

次の例では、include 演算子に基づいて、 Blog、ところが、Select演算子を使用して、匿名型を取得するクエリを変更します。In the following example, the include operators are based on the Blog, but then the Select operator is used to change the query to return an anonymous type. この場合、include 演算子がある影響しません。In this case, the include operators have no effect.

using (var context = new BloggingContext())
{
    var blogs = context.Blogs
        .Include(blog => blog.Posts)
        .Select(blog => new
        {
            Id = blog.BlogId,
            Url = blog.Url
        })
        .ToList();
}

既定では、EF コアが、警告をログとは、演算子は無視されます。By default, EF Core will log a warning when include operators are ignored. 参照してくださいログログ出力を表示する方法の詳細についてです。See Logging for more information on viewing logging output. スローするか、何もする include 演算子が無視される動作を変更できます。You can change the behavior when an include operator is ignored to either throw or do nothing. では通常、コンテキストでのオプションを設定するときにこれは、 DbContext.OnConfiguring、またはStartup.csASP.NET Core を使用している場合。This is done when setting up the options for your context - typically in DbContext.OnConfiguring, or in Startup.cs if you are using ASP.NET Core.

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder
        .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFQuerying;Trusted_Connection=True;ConnectRetryCount=0")
        .ConfigureWarnings(warnings => warnings.Throw(CoreEventId.IncludeIgnoredWarning));
}

明示的読み込みExplicit loading

注意

この機能は、EF コア 1.1 で導入されました。This feature was introduced in EF Core 1.1.

使用して、ナビゲーション プロパティを明示的に読み込むことができます、 DbContext.Entry(...) API です。You can explicitly load a navigation property via the DbContext.Entry(...) API.

using (var context = new BloggingContext())
{
    var blog = context.Blogs
        .Single(b => b.BlogId == 1);

    context.Entry(blog)
        .Collection(b => b.Posts)
        .Load();

    context.Entry(blog)
        .Reference(b => b.Owner)
        .Load();
}

ナビゲーション プロパティは、関連エンティティを返す別のクエリを実行することによっても明示的に読み込むことができます。You can also explicitly load a navigation property by executing a seperate query that returns the related entities. 変更の追跡が有効になっているかどうか、EF コアのすべてのエンティティは既に読み込まれているを参照する新たに読み込まれたエンティティのナビゲーション プロパティを設定を参照してくださいに既に読み込まれているエンティティのナビゲーション プロパティを設定が自動的にエンティティを読み込むときに、新たに読み込まれたエンティティです。If change tracking is enabled, then when loading an entity, EF Core will automatically set the navigation properties of the newly-loaded entitiy to refer to any entities already loaded, and set the navigation properties of the already-loaded entities to refer to the newly-loaded entity.

LINQ クエリを表すナビゲーション プロパティの内容を取得することもできます。You can also get a LINQ query that represents the contents of a navigation property.

これにより、それらをメモリに読み込むことがなく、関連エンティティを aggregate 操作を実行しているなどの作業を行うことができます。This allows you to do things such as running an aggregate operator over the related entities without loading them into memory.

using (var context = new BloggingContext())
{
    var blog = context.Blogs
        .Single(b => b.BlogId == 1);

    var postCount = context.Entry(blog)
        .Collection(b => b.Posts)
        .Query()
        .Count();
}

関連エンティティは、メモリに読み込まれるをフィルターすることもできます。You can also filter which related entities are loaded into memory.

using (var context = new BloggingContext())
{
    var blog = context.Blogs
        .Single(b => b.BlogId == 1);

    var goodPosts = context.Entry(blog)
        .Collection(b => b.Posts)
        .Query()
        .Where(p => p.Rating > 3)
        .ToList();
}

遅延読み込みLazy loading

遅延読み込みが EF のコアでまだサポートされていません。Lazy loading is not yet supported by EF Core. 表示することができます、遅延読み込みバックログ項目に、この機能を追跡するためにします。You can view the lazy loading item on our backlog to track this feature.

EF コアは自動的に修正をナビゲーション プロパティ、しまうサイクルで、オブジェクト グラフ内ためです。Because EF Core will automatically fix-up navigation properties, you can end up with cycles in your object graph. たとえば、ブログを読み込みが関連付けられて投稿投稿のコレクションを参照するブログ オブジェクトになります。For example, Loading a blog and it's related posts will result in a blog object that references a collection of posts. これらの投稿の各ブログへの参照になります。Each of those posts will have a reference back to the blog.

一部のシリアル化フレームワークでは、このようなサイクルは許可されません。Some serialization frameworks do not allow such cycles. たとえば、Json.NET であっても、循環参照が発生したときの場合、次の例外がスローされます。For example, Json.NET will throw the following exception if a cycle is encoutered.

Newtonsoft.Json.JsonSerializationException: 自己のループを型 'MyApplication.Models.Blog' と 'ブログ' プロパティの検出を参照します。Newtonsoft.Json.JsonSerializationException: Self referencing loop detected for property 'Blog' with type 'MyApplication.Models.Blog'.

ASP.NET Core を使用している場合は、オブジェクト グラフ内で見つかったサイクルを無視する Json.NET を構成できます。If you are using ASP.NET Core, you can configure Json.NET to ignore cycles that it finds in the object graph. これには、ConfigureServices(...)メソッドStartup.csです。This is done in the ConfigureServices(...) method in Startup.cs.

public void ConfigureServices(IServiceCollection services)
{
    ...

    services.AddMvc()
        .AddJsonOptions(
            options => options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
        );

    ...
}