如果我想在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>>
指定的"包含"关系。
有什么建议吗?
将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链接
这在EF6中是不可能的,我不认为EF Core会改变这一点。这是因为Find
方法的主要目的是从本地缓存中获取已经加载的实体,或者从数据库中加载它(如果它不在那里)。因此,急于加载(Include
)只能在后一种情况下使用,而在前一种情况下,它需要执行显式加载。将两者结合在一个方法中在技术上可能是可行的,但很难。
我认为你应该采取FirstOrDefault
(或SingleOrDefault
)路线,并结合急切加载。您可以在Repository通用方法GetById中看到EF6使用即时加载的样例实现。它可以为EF Core进行调整,比如使用dbContext.Model.FindEntityType(typeof(T)).FindPrimaryKey().Properties
来查找PK属性并构建谓词。此外,由于EF Core包含有点复杂(需要Include
/ThenInclude
链),你可能会发现有趣的是,这个线程可以在实体框架核心中创建一个基于字符串的包含替代方案吗?