Tengo problemas para evitar repetir la lógica de proyección cuando uso la herencia en EF Core .
Aquí está mi escenario: tengo tres tipos:
Lesson (que es una clase abstracta) (Propiedades: Id , Title , etc.)ArticleLesson (que hereda de Lesson ) (Propiedades: Content , TotalWoddsCount , etc.)VideoLesson (que hereda de Lesson ) (Propiedades: VideoUrl , Duration , etc.)Casi todo lo maneja correctamente EF Core, y estoy usando el enfoque de tabla por jerarquía (TPH) predeterminado.
El problema surge cuando quiero recuperar lecciones de la base de datos y necesito algunas de las columnas compartidas entre ArticleLesson y VideoLesson (es decir, algunas de las propiedades de Lesson ), ADEMÁS, algunas de las propiedades específicas de ArticleLesson o VideoLesson . Esta es la expresión que se me ocurrió:
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(); Como puede ver, estoy repitiendo la parte de propiedades compartidas, dos veces. Solo hay 2 propiedades que se repiten en este ejemplo, Id y Title , pero en el mundo real puede tener docenas de estas; y tener que repetirlos todos así sería una h.
¿Hay alguna manera de hacer que esta expresión de proyección sea más sucinta y evitar la repetición?
Puede agregar un constructor a LessonDto , ArticleLessonDto y VideoLessonDto que acepte las diferentes propiedades compartidas.
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();