实体框架不会查询派生类 - DbOfTypeExpression中的错误 [英] Entity Framework doesn't query derived classes - Error in DbOfTypeExpression

查看:110
本文介绍了实体框架不会查询派生类 - DbOfTypeExpression中的错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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



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



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



我已经使用着名的Fruit-Example来演示问题:

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


//
//计划是在mvc视图中使用此属性
//
[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
返回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>()。包含(o => o.OrangeFruitness)
.ToList());

我得到的错误信息是:



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



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



任何帮助都非常感谢!

解决方案

据我所知,在单个数据库查询中,您无法在多个子类型上应用 Include 。您可以查询一个类型( OfType< Apple>()。Include(a => a.AppelFruitness))和另一个类型相同。问题是,您不能将结果与同一查询结合在一起,因为结果集合具有不同的通用类型(苹果和橙子)。



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



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

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

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

 列表< 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 )当实体附加到上下文(Relationship fixup)时,导航属性会自动填充,这意味着您可以从viewModel集合中提取果实...

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

...你会得到包括 FruitnessFactor 属性。



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




I have a base class and two derived classes.

Each of the derived classes implements the same type as a property - the only difference is the property name.

Sadly I don't have much influence on the class design -> they have been generated from a wsdl file.

I then have a property on the BaseType to encapsulate the common property. The plan was to use this property in my web views etc.

I have used the famous "Fruit-Example" to demonstrate the problem:

 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 { }

In my MVC controller, the following query works absolutely fine:

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

But this one doesn't:

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

The error message I get is:

DbOfTypeExpression requires an expression argument with a polymorphic result type that is compatible with the type argument.

I am using EF 5.0 RC and the Code First approach.

Any help is much appreciated!

解决方案

As far as I can tell you can't apply Include on multiple subtypes in a single database query. You can query one type (OfType<Apple>().Include(a => a.AppelFruitness)) and the same for another subtype. The problem is that you can't concat the results in the same query because the result collections have different generic types (apples and oranges).

One option would be to run two queries and copy the result collection into a new collection of the base type - as you already indicated in the comment section under your question.

The other option (which would only need a single query) is a projection. You would have to define a projection type (you could also project into an anonymous type)...

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

...and then can use the query:

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();

If you don't disable change tracking (by using AsNoTracking) the navigation properties get populated automatically when the entities get attached to the context ("Relationship fixup") which means that you can extract the fruits from the viewModel collection...

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

...and you'll get the fruits including the FruitnessFactor properties.

This code is pretty awkward but a direct approach without using a projection has been asked for several times without success:

这篇关于实体框架不会查询派生类 - DbOfTypeExpression中的错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆