将Include()与继承的实体一起使用

Pet*_*nar 12 inheritance entity-framework join eager-loading

在EF eager中,加载相关实体很容易.

但是在使用table-per-type模型加载数据时,我遇到了包括继承实体在内的困难.

这是我的模特:

实体:

  • ArticleBase (基础文章实体)
    • ArticleSpecial(继承自ArticleBase)
  • UserBase (基本用户实体)
    • UserSpecial(继承自UserBase)
  • Image

关系如图所示(省略许多列): alt text http://i48.tinypic.com/5x4kdc.jpg

实际上,我的用户总是类型UserSpecial,因为UserBase在另一个应用程序中使用,因此我们可以共享凭据.这是我有两个单独的表的唯一原因.UserBase表格不能以任何形式或形式进行更改,因为其他应用程序会破坏.

我怎么想加载ArticleSpecialCreatedByEditedBy设置,使两者都是类型UserSpecial(定义Image关系)?


我尝试过这些选项(虽然不成功):

1. 使用lambda表达式:

context.ArticleBases
    .OfType<ArticleSpecial>()
    .Include("UserCreated.Image")
    .Include("UserEdited.Image");
Run Code Online (Sandbox Code Playgroud)

在这种情况下,问题是,无论是CreatedByEditedBy相关的UserBase,没有定义Image导航.所以我应该以某种方式将这两个UserSpecial类型转换为:

context.ArticleBases
    .OfType<ArticleSpecial>()
    .Include("UserCreated<UserSpecial>.Image")
    .Include("UserEdited<UserSpecial>.Image");
Run Code Online (Sandbox Code Playgroud)

但当然使用泛型Include("UserCreated<UserSpecial>.Image")不起作用.

2. 我尝试过使用LINQ查询

var results = from articleSpecial in ctx.ArticleBase.OfType<ArticleSpecial>()
                  join created in ctx.UserBase.OfType<UserSpecial>().Include("Image")
                  on articleSpecial.UserCreated.Id equals created.Id
                  join edited in ctx.UserBase.OfType<UserSpecial>().Include("Image")
                  on articleSpecial.UserEdited.Id equals edited.Id   
              select articleSpecial;
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我只获取ArticleSpecial没有设置相关属性的对象实例.我知道我应该以某种方式选择那些,但我不知道怎么做?

在我的LINQ中选择部分可以改为类似的东西

select new { articleSpecial, articleSpecial.UserCreated, articleSpecial.UserEdited };
Run Code Online (Sandbox Code Playgroud)

但图像仍未加载到我的上下文中.我在这种情况下的联接几乎不用于过滤articleSpecial结果,但它们不会将实体加载到上下文中(我想).

Enr*_*lio 3

这似乎是当前版本的 Entity Framework (1.0) 的限制,看看这个相关的 SO 问题

在您的情况下,在投影中包含相关的UserCreatedUserEdited属性是正确的解决方案。但是,如果您还想填充UserSpecial对象上的Image属性,则必须确保也包含该属性:

var results = from articleSpecial in ctx.ArticleBase.OfType<ArticleSpecial>()
              select new
              {
                  articleSpecial,
                  articleSpecial.UserCreated,
                  ((UserSpecial)articleSpecial.UserCreated).Image,
                  articleSpecial.UserEdited,
                  ((UserSpecial)articleSpecial.UserEdited).Image
              };
Run Code Online (Sandbox Code Playgroud)

当然,此查询建立在所有 ArticleSpecial 实体始终引用 UserSpecial 实体的假设之上,否则转换将失败。
如果此假设并不总是成立,您可以使用 LINQ 扩展方法和多行 lambda 函数来表达相同的查询来执行安全转换:

var results = ctx.ArticleBase
                 .OfType<ArticleSpecial>()
                 .AsEnumerable()
                 .Select(a =>
                  {
                      var userCreated = a.UserCreated as UserSpecial;

                      if (userCreated != null)
                      {
                          var image = userCreated.Image;
                      }

                      var userEdited = a.UserEdited as UserSpecial;

                      if (userEdited != null)
                      {
                          var image = userEdited.Image;
                      }

                      return a;
                  });
Run Code Online (Sandbox Code Playgroud)

在后一个示例中,您也不需要在结果中包含UserSpecialImage实体。相反,您只需在投影阶段访问ArticleSpecial实体上的导航属性,即可强制实体框架预先加载相关对象。