【问题标题】:Entity Framework - Including Collections on Derived from Base DBSet实体框架 - 包括派生自基础 DBSet 的集合
【发布时间】:2015-11-18 03:08:58
【问题描述】:

我要问的主要问题是:

有没有办法保持基于基类的 DbSet 并且仍然支持在仅需要 Id 的单个检索方法中对 Derived 对象进行预加载?答案可能是你不能。我只是希望我忽略了一些东西。

考虑以下情况:

//Models
public class Base {
    public int Id {get;set;}
    public string BaseProp {get;set;}
}

public class Derived : Base {
    public string DerivedProp {get;set;}
}

//Context
DbSet<Base> Bases {get;set;}

//Saving
public void Save(Base obj){
    // Adding only for brevity
    context.Bases.Add(obj)
    context.SaveChanges();
}

//Retrieval
public Base Retrieve(int id){
    return context.Bases.FirstOrDefault(x => x.Id == id);
}

EF6 足够聪明,可以知道 Base 对象何时实际上是 Derived 对象,并在保存时填充其他字段并将对象检索为 Derived 对象。

但是,如果我将派生类更改为:

public class Derived : Base {
    public string DerivedProp {get;set;}
    public ICollection<SomeLookup> Lookup {get; set;}  // Creates junction table with Id/LookupId as columns
}

我仍然可以保存(并且它使用选定的查找很好地填充了联结表),但我不再可以检索我的 Base DbSet 中的完整对象,因为我无法将它更改为在一个集合中包含一个热切的包含基地不知道存在。

我可以虚拟化集合,以便在映射发生时延迟加载,但我想知道,这是根本问题:


更新:基本上我想知道的是,如果我只有一个 Id 可用于我的检索,那么以下内容将不起作用,但有类似的东西吗?

context.Bases.Include(x => ((Derived)x).Lookup).FirstOrDefault(x => x.Id == id)

用例是我有一个列表页面。该页面不需要关心它是什么类型,因为它只有基本属性。如果我进入其中一个编辑页面,服务器只会传递 ID。

如果这是我在检索后构建 DTO 时会发生的唯一方法,我会接受延迟加载,但我想知道是否有一些我不知道的 EF 配置用于 modelBuilder 或如何编写一个我尚未找到的项目查询,该查询允许对该派生查找集合进行急切加载?

更新 2: 基于他让我知道我不能做我希望的事情而接受的答案。还发现了this on the EF uservoice

【问题讨论】:

  • 你能展示从数据库获取数据的代码吗?当您获得基本 dbset 并需要包含派生导航属性时,用例是什么?
  • @KirillBestemyanov 我更新了这个问题。很可能允许延迟加载很好,我只是无缘无故地过早优化(谁知道,结果 SQL 可能更糟)。我只是好奇这样的东西是否真的可以工作,因为我什至惊讶于 Base & Derived 的东西和开箱即用的效果一样好。
  • 你知道当前 id 的派生类型是什么吗?如果是,您可以使用泛型 Set

标签: c# entity-framework ef-code-first


【解决方案1】:

基本上我想知道的是,如果我只有一个 Id 可用于我的检索,则以下内容将不起作用,但有类似的东西吗?

如果您的派生对象使用某种类型的实体框架继承; Mapping the Table-Per-Type (TPT) InheritanceMapping the Table-Per-Hierarchy (TPH) InheritanceMapping the Table-Per-Concrete Class (TPC) Inheritance

然后是的

db.Bases
  .OfType<Derived>()
  .Include(d => d.Lookup)
  .Where(d => d.Id = someId)
  .ToList();

否则不行,就不行了。

【讨论】:

  • 我花了一些时间摆弄这些,但似乎没有一个适合。奇怪,因为我认为我没有做任何特别的事情,所以我会认为我会成为默认值。当 Id 只是一个 Base 时,TypeOf 刚刚返回空值。也就是说,感谢您的洞察力,因为它看起来不太可能满足我的需求,因为我还发现了这一点:data.uservoice.com/forums/…
  • 那么您正在使用其中一种受支持的继承类型?
  • 我想我有一点不愉快。我有带有一些通用基本属性的 TPH,但是 TPT 用于非抽象类的真实类型差异。样式的合并仍然让我可以进行非常简单的实体 linq 查询,只是缺少这一点用于派生包含,显然不支持。非常感谢您的洞察力。
  • LINQ 扩展方法是OfType&lt;&gt; 而不是TypeOf&lt;&gt;,如图所示。我要求进行修改,但如果它从未获得批准,请注意。
最近更新 更多