对继承的实体使用 Include()

发布于 2024-08-22 19:03:46 字数 2543 浏览 10 评论 0原文

在 EF 中,预加载相关实体简单

但是,在使用每种类型表模型加载数据时,我包括继承的实体遇到了困难。

这是我的模型:

实体

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

Relations 如图所示(省略了很多列): 替代文本

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

问题

我该如何加载设置了CreatedByEditedByArticleSpecial,以便两者都是UserSpecial<类型/code> (定义 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.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 };

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

In EF eager loading related entities is easy.

But I'm having difficulties including inherited entities when loading data using table-per-type model.

This is my model:

Entities:

  • ArticleBase (base article entity)
    • ArticleSpecial (inherited from ArticleBase)
  • UserBase (base user entity)
    • UserSpecial (inherited from UserBase)
  • Image

Relations are as shown on the image (omitting many columns):
alt text

In reality my users are always of type UserSpecial, since UserBase is used in another application, thus we can share credentials. That's the only reason I have two separate tables. UserBase table can't be changed in any way shape or form, because the other app would break.

Question

How am I suppose to load ArticleSpecial with both CreatedBy and EditedBy set, so that both are of type UserSpecial (that defines Image relation)?


I've tried (unsuccessfully though) these options:

1.
Using lambda expressions:

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

In this case the problem is that both CreatedBy and EditedBy are related to UserBase, that doesn't define Image navigation. So I should somehow cast these two to UserSpecial type like:

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

But of course using generics in Include("UserCreated<UserSpecial>.Image") don't work.

2.
I have tried using LINQ query

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;

In this case I'm only getting ArticleSpecial object instances without related properties being set. I know I should select those somehow, but I don't know how?

Select part in my LINQ could be changed to something like

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

but images are still not loaded into my context. My joins in this case are barely used to filter out articleSpecial results, but they don't load entities into context (I suppose).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

复古式 2024-08-29 19:03:46

这似乎是当前版本的实体框架(1.0)的限制看看这个相关所以问题

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

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

This seems to be a limitation in the current version of Entity Framework (1.0) Have a look at this related SO question.

In your case including the related UserCreated and UserEdited properties in the projection is the right solution. However if you also want to populate the Image property on the UserSpecial object, you must be sure to include that as well:

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

Of course this query builds on the assumption that all ArticleSpecial entities always refer to a UserSpecial entity, otherwise the casting will fail.
If this assumption isn't always true, you could express the same query using the LINQ extension methods and a multi-line lambda function to perform a safe casting:

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

In the latter example, you also do not need to include UserSpecial and Image entities in the results. Instead you just need to access the navigation properties on the ArticleSpecial entities during the projection phase in order to force Entity Framework to eager load the related objects.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文