在同一个查询上使用.Find()和.Include()

joh*_* Gu 32 entity-framework

我有以下方法从脚手架模板自动生成存储库: -

public Group Find(int id)
{
    return context.Groups.Find(id);
}
Run Code Online (Sandbox Code Playgroud)

但由于组对象有哪些我需要两个导航属性,所以我想包括.Include,所以我代替.find.where: -

public Group Find(int id)
{
    return context.Groups.Where(c=>c.GroupID==id)
                         .Include(a => a.UserGroups)
                         .Include(a2 => a2.SecurityRoles)
                         .SingleOrDefault();
}
Run Code Online (Sandbox Code Playgroud)

但我的问题是我怎么能应用.Include.find()而是采用.Where()

Not*_*ple 39

我只是想着实际发现了什么.@lazyberezovsky是正确的包括,并发现不能相互结合使用.我认为这是非常慎重的,这就是为什么:

DbSet上的Find方法使用主键值来尝试查找上下文跟踪的实体.如果在上下文中找不到该实体,则将向数据库发送查询以在那里找到该实体.如果在上下文或数据库中找不到实体,则返回Null.

查找与以下两种重要方式使用查询不同:

  • 只有在上下文中找不到具有给定键的实体时,才会往返数据库.
  • Find将返回处于已添加状态的实体.也就是说,Find将返回已添加到上下文但尚未保存到数据库的实体.

(来自http://msdn.microsoft.com/en-us/data/jj573936.aspx)

因为find是一种优化方法,所以可以避免需要访问服务器.如果您已经跟踪了实体,这很好,因为EF可以更快地返回它.

但是,如果它不仅仅是我们所追求的这个实体(例如我们想要包含一些额外的数据),那么就无法知道这些数据是否已经从服务器加载.虽然EF可能与连接一起进行此优化,但由于它对数据库状态做出假设,因此容易出错.

我认为包含并发现​​无法一起使用是一个非常慎重的决定,以确保数据完整性和不必要的复杂性.当您想要进行连接以始终转到数据库以执行该连接时,它会更清晰,更简单.


Ser*_*kiy 6

你不能.查找DbSet<T>类型上定义的方法,它返回实体.你不能打电话Include的实体,那么唯一可能的选项调用Find Include.你需要DbSet<T>输入,但Include("UserGroups")会返回DbQuery<T>,并且Include(g => g.UserGroups)还会返回DbQuery<T>:

public static IQueryable<T> Include<T>(this IQueryable<T> source, string path) 
    where T: class
{
    RuntimeFailureMethods.Requires(source != null, null, "source != null");
    DbQuery<T> query = source as DbQuery<T>;
    if (query != null)    
        return query.Include(path); // your case
    // ...
}
Run Code Online (Sandbox Code Playgroud)

DbQuery<T>因此不是孩子的DbSet<T>方法Find是不可用的.还要记住,Find首先在本地对象中查找实体.如果它们没有加载,它将如何包含一些引用的实体?

  • 在那个说明中,我不是一个巨大的粉丝,无论如何,.FirstOrDefault()或.SingleOrDefault()实现了类似的目的,并在任何IEnumerable上工作 (3认同)