12

在 EF 中急切加载相关实体很容易

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

这是我的模型:

实体

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

关系如图所示(省略许多列): 替代文字

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

问题

我应该如何加载ArticleSpecial两者CreatedByEditedBy设置,以便两者都是类型UserSpecial(定义Image关系)?


我已经尝试过(虽然没有成功)这些选项:

1. 使用 lambda 表达式:

context.ArticleBases
    .OfType<ArticleSpecial>()
    .Include("UserCreated.Image")
    .Include("UserEdited.Image");

在这种情况下,问题在于两者CreatedByEditedBy都与 相关UserBase,这没有定义Image导航。所以我应该以某种方式将这两个UserSpecial类型转换为:

context.ArticleBases
    .OfType<ArticleSpecial>()
    .Include("UserCreated<UserSpecial>.Image")
    .Include("UserEdited<UserSpecial>.Image");

但是当然使用泛型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;

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

我的 LINQ 中的选择部分可以更改为类似

select new { articleSpecial, articleSpecial.UserCreated, articleSpecial.UserEdited };

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

4

1 回答 1

3

这似乎是当前版本的 Entity Framework (1.0) 中的一个限制。看看这个相关的 SO question

在您的情况下,在投影中包含相关的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
              };

当然,此查询建立在所有 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;
                  });

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

于 2010-03-30T19:59:31.243 回答