【问题标题】:How to avoid repeating property projections when using EF Core inheritance?使用 EF Core 继承时如何避免重复属性投影?
【发布时间】:2021-07-23 03:10:26
【问题描述】:

在使用inheritance in EF Core 时,我正在努力避免重复投影逻辑。

这是我的场景:我有三种类型:

  1. Lesson(这是一个抽象类)(属性:IdTitle 等)
  2. ArticleLesson(继承自Lesson)(属性:ContentTotalWoddsCount等)
  3. VideoLesson(继承自Lesson)(属性:VideoUrlDuration等)

几乎所有事情都由 EF Core 正确处理,我使用的是默认的 Table-Per-Hierarchy (TPH) 方法。

当我想从数据库中检索课程并且我需要ArticleLessonVideoLesson 之间的一些共享列(即Lesson 的一些属性)时,就会出现问题,另外,还有一些特定于属性到ArticleLessonVideoLesson。这是我想出的表达方式:

var r1 = dbContext.Lessons.Select<Lesson, LessonDto>(l =>
    l is ArticleLesson
    ? new ArticleLessonDto
    {
        Id = l.Id, // This is repeated below
        Title = l.Title, // This is repeated below
        // ...other properties that I would have to repeat below
        Content = (l as ArticleLesson).Content,
    }
    : l is VideoLesson
    ? new VideoLessonDto
    {
        Id = l.Id, // This is repeated above
        Title = l.Title, // This is repeated above
        // ...other properties that I would have to repeat above
        VideoUrl = (l as VideoLesson).VideoUrl,
    }
    : null
)
.ToList();

如您所见,我将共享属性部分重复了两次。在这个例子中只有两个属性被重复,IdTitle,但在现实世界中你可以有几十个;并且不得不像这样重复所有这些将是一个h。

有什么办法可以让这个投影表达式更简洁,避免重复?

【问题讨论】:

  • 简短回答:此类实施的努力将会很高。最好在这个地方复制/粘贴。如果您有大量此类案例,请收集它们并创建新问题。

标签: c# entity-framework linq entity-framework-core


【解决方案1】:

您可以向您的LessonDtoArticleLessonDtoVideoLessonDto 添加一个接受不同共享属性的构造函数。

    public class LessonDto
    {
        public LessonDto(int id, ... other)
        {
            Id = id;
            // ...
        }

        public int Id { get; set; }
    }

    public class ArticleLessonDto : LessonDto
    {
        public ArticleLessonDto(LessonDto dto) : base(dto.Id)
        {

        }

        public string Content { get; set; }
    }

    var r1 = dbContext.Lessons
        .Select(l => new
        {
            dto = new LessonDto(l.Id, ... other),
            full = l
        })
        .Select(row => row.full is ArticleLesson
        ? new ArticleLessonDto(row.dto)
        {
            Content = (row.full as ArticleLesson).Content,
        }
        : row.full is VideoLesson
        ? new VideoLessonDto(row.dto)
        {
            VideoUrl = (row.full as VideoLesson).VideoUrl,
        }
        : (LessonDto)null
    )
    .ToList();

【讨论】:

  • 不幸的是,将 l 传递给 ArticleLessonDtoVideoLessonDto 的构造函数(或者也将它传递给任何无法识别的方法,就此而言)将导致 EF Core 检索其所有列来自数据库的行;这是低效的。
  • @Arad 抱歉,我错过了这个要求。要减少带宽,只需有一个接受所需共享参数的构造函数。我针对这种情况更新了我的答案。 (通过 SQL Server 提供程序验证)
  • 好吧,这又是同一个故事,你最终重复了两次共享属性,一次是VideoLessonDto,一次是ArticleLessonDto;这是我们一开始就想避免的事情:(
  • @Arad 这实际上减少了 50% 的代码,因为您不必重复所有的任务。但是,嘿-也有解决方案。更新了我的答案:)
  • 谢谢!我会检查一下。不过,我希望新的更新版本不会导致所有列都被检索到。但它仍然很聪明。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-13
  • 1970-01-01
  • 2011-05-18
  • 1970-01-01
相关资源
最近更新 更多