如何在DbSet.Find()中包含相关表?

时间:2016-09-11 09:53:26

标签: c# entity-framework-core

如果我想在EF7查询中包含相关对象,那就很简单了:

var myThing = db.MyThings
                .Include(t => t.RelatedThing)
                .Where(t => t.SomeCondition == true)
                .ToList();

此外,DbSet<T>上有一个很好的方法可以很容易地通过其键加载单个对象:

var myThing = db.MyThings.Find(thingId);

但现在我想通过其ID myThing及其RelatedThing加载.Find()。不幸的是(并且可以理解)DbSet<T>IQueryable<T>的方法,而非var myThing = db.MyThings .Include(t => t.RelatedThing) .SingleOrDefault(t => t.MyThingId == thingId); 。显然我可以这样做:

.Find()

但我特别想使用Expression<Func<T, object>>方法,因为它很好且通用,而且我正在编写一个通常加载记录的方法以及{ "result": 0, "metadata": [ ], "checksums": [ ], "fileids": [ ] } 指定的“包含”关系。 / p>

有任何建议怎么做?

2 个答案:

答案 0 :(得分:5)

将Find与Load结合使用,以显式加载相关实体。 在MSDN示例下面:

using (var context = new BloggingContext()) 
{ 
  var post = context.Posts.Find(2); 

  // Load the blog related to a given post 
  context.Entry(post).Reference(p => p.Blog).Load(); 

  // Load the blog related to a given post using a string  
  context.Entry(post).Reference("Blog").Load(); 

  var blog = context.Blogs.Find(1); 

  // Load the posts related to a given blog 
  context.Entry(blog).Collection(p => p.Posts).Load(); 

  // Load the posts related to a given blog  
  // using a string to specify the relationship 
  context.Entry(blog).Collection("Posts").Load(); 
}

这里是MSDN link

答案 1 :(得分:2)

EF6无法实现,我认为EF Core不会改变它。这是因为Find方法的主要目的是从本地缓存中引入已加载的实体,或者如果不存在则从数据库加载它。因此,急切加载(Include)只能在后一种情况下使用,而在前者中则需要执行显式加载。将这两种方法结合在一起可能在技术上是可行的,但很难。

我认为您应该将FirstOrDefault(或SingleOrDefault)路线与急切加载相结合。您可以在Repository generic method GetById using eager loading中查看EF6的示例实现。可以使用dbContext.Model.FindEntityType(typeof(T)).FindPrimaryKey().Properties来调整EF Core,以查找PK属性并构建谓词。此外,由于EF Core包含的内容有点复杂(需要Include / ThenInclude个链),您可能会发现这个帖子Can a String based Include alternative be created in Entity Framework Core?很有意思。