【问题标题】:Entity Framework doesn't query derived classes - Error in DbOfTypeExpression实体框架不查询派生类 - DbOfTypeExpression 中的错误
【发布时间】:2012-06-15 03:43:26
【问题描述】:

我有一个基类和两个派生类。

每个派生类都实现了与属性相同的类型 - 唯一的区别是属性名称。

遗憾的是,我对类设计没有太大影响 -> 它们是从 wsdl 文件生成的。

然后我在 BaseType 上有一个属性来封装公共属性。计划是在我的网络视图等中使用此属性。

我用著名的“Fruit-Example”来演示这个问题:

 public class FruitBase
    {
        public virtual int ID { get; set; }


        //
        // The plan is to use this property in mvc view
        //
        [NotMapped]
        public virtual FruitnessFactor Fruitness
        {
            get
            {
                if (this.GetType().BaseType == typeof(Apple))
                    return ((Apple)this).AppleFruitness;
                else if (this.GetType().BaseType == typeof(Orange))
                    return ((Orange)this).OrangeFruitness;
                else
                    return null;
            }
        }
    }

public class FruitnessFactor { }

在我的 MVC 控制器中,以下查询绝对可以正常工作:

return View(context.FruitEntities
                           .OfType<Apple>().Include(a =>a.AppleFruitness)
                           .ToList());

但是这个没有:

  return View(context.FruitEntities
                                   .OfType<Apple>().Include(a =>a.AppleFruitness)
                                   .OfType<Orange>().Include(o => o.OrangeFruitness)
                                   .ToList());

我得到的错误信息是:

DbOfTypeExpression 要求表达式参数具有与类型参数兼容的多态结果类型。

我正在使用 EF 5.0 RC 和 Code First 方法。

非常感谢任何帮助!

【问题讨论】:

  • 这可能是因为您的表达暗示OrangeApple
  • 我会认为通过将我的 FruitEntities 定义为 DbSet&lt;FruitBase&gt; FruitEntities 表达式意味着橙子和苹果是水果?!
  • OfType 链说:“从 FruitEntities 过滤所有苹果,然后从结果中过滤所有橙子的苹果”,这仅在橙子是苹果时才有意义,即 Orange 类继承自Apple 班级。你想用那个查询实现什么?橙子和苹果的组合列表,即所有苹果橙子的水果?
  • 我想将所有水果的列表返回到视图,然后显示 FruitBase.FruitnessFactor。我可以看到OfType 在这种情况下没有意义。 “手动”替代方法是先查询橙子,然后再查询苹果,将两者合并到 List 中。这似乎可行,但代码有异味
  • 其实闻起来是手动查询子类型。依靠多态才是正道。

标签: entity-framework linq-to-entities ef-code-first polymorphism entity-framework-5


【解决方案1】:

据我所知,您不能将Include 应用于单个数据库查询中的多个子类型。您可以查询一种类型 (OfType&lt;Apple&gt;().Include(a =&gt; a.AppelFruitness)) 并查询另一种子类型。问题是您不能在同一个查询中连接结果,因为结果集合具有不同的泛型类型(苹果和橙子)。

一种选择是运行两个查询并将结果集合复制到基本类型的新集合中 - 正如您已在问题下方的评论部分中指出的那样。

另一个选项(只需要一个查询)是投影。你必须定义一个投影类型(你也可以投影到一个匿名类型)......

public class FruitViewModel
{
    public FruitBase Fruit { get; set; }
    public FruitnessFactor Factor { get; set; }
}

...然后可以使用查询:

List<FruitViewModel> fruitViewModels = context.FruitEntities
    .OfType<Apple>()
    .Select(a => new FruitViewModel
    {
        Fruit = a,
        Factor = a.AppleFruitness
    })
    .Concat(context.FruitEntities
    .OfType<Orange>()
    .Select(o => new FruitViewModel
    {
        Fruit = o,
        Factor = o.OrangeFruitness
    }))
    .ToList();

如果您不禁用更改跟踪(通过使用AsNoTracking),导航属性会在实体附加到上下文(“关系修复”)时自动填充,这意味着您可以从 viewModel 集合中提取结果...

IEnumerable<FruitBase> fruits = fruitViewModels.Select(fv => fv.Fruit);

...您将获得成果包括FruitnessFactor 属性。

这段代码很尴尬,但不使用投影的直接方法被问了好几次都没有成功:

【讨论】:

  • 我想我会选择 2 查询解决方案。如果考虑到我需要进行排序、分页和类似的事情,我只担心会影响性能。但到目前为止,它看起来不错。干杯!
猜你喜欢
  • 1970-01-01
  • 2012-04-10
  • 1970-01-01
  • 1970-01-01
  • 2014-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多