首页 > 解决方案 > 使用 EF Core 继承时如何避免重复属性投影?

问题描述

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

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

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

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

当我想从数据库中检索课程并且我需要 and 之间的一些共享列ArticleLessonVideoLesson即 的某些属性Lesson)、PLUS 以及特定于ArticleLessonor的某些属性时,就会出现问题VideoLesson。这是我想出的表达方式:

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

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

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

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

解决方案


您可以将构造函数添加到您的LessonDto,ArticleLessonDtoVideoLessonDto接受不同的共享属性。

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

推荐阅读