在实体框架中使用自定义表达式嵌套包含集合
本文关键字:表达式 嵌套 包含 集合 自定义 实体 框架 | 更新日期: 2023-09-27 18:15:21
根据这篇文章,将私有集合属性暴露给实体框架,我试图保持模型中的集合属性不被暴露。这里展示的技术可以很好地用于单个关卡,但我无法将其用于多个关卡。
在我的示例模型中,我有训练器。培训师有培训课程。培训班有培训班。我在Trainer中定义了以下内容:
public class ORMappings
{
public const string TrainingCoursesCollectionName = nameof(Trainer._trainingCourses);
public static Expression<Func<Trainer, ICollection<TrainingCourse>>> TrainingCourses
{
get { return t => t._trainingCourses; }
}
}
这很好(包括一个集合深度),我可以像这样引用它:
return _dbContext.Set<Trainer>()
.Include(Trainer.ORMappings.TrainingCoursesCollectionName);
或
// using System.Data.Entity extension
return _dbContext.Set<Trainer>()
.Include(Trainer.ORMappings.TrainingCourses);
我指的是关于如何包含嵌套集合属性的文档。它建议以下操作应该起作用:
先包含一个集合,然后再下一个集合:查询包含(e => e. level1collection)。选择(l1 =>l1.Level2Collection)) .
然而,我似乎找不到一种方法来使用。select()包括使用上面所示的强类型表达式的每个TrainingCourse引用的TrainingClasses (TrainingCourse有一个类似的ORMappings类的TrainingClasses列表)。我是否尝试在ORMappings类之外这样做(例如在存储库或类似的地方),或者在我可以直接访问我的私人_trainingCourses列表的地方,这并不重要。我很高兴有一个单独的ORMappings表达式,除了TrainingCourses,还包括TrainingClasses,如果我能让它工作的话。我的目标是能够指定应该在集合树中填充对象的深度,以便只在给定操作需要时加载数据。
作为额外参考,以下是Trainer如何定义其与TrainingCourse的关系:
private List<TrainingCourse> _trainingCourses { get; } = new List<TrainingCourse>();
public IEnumerable<TrainingCourse> TrainingCourses
{
get
{
return _trainingCourses
.Where(tc => tc.IsActive)
.AsEnumerable();
}
}
好吧,恕我冒昧,我认为你正在尝试做一些非常奇怪的事情。如果您想"保护"源代码,您应该尝试探索封装关键字,如internal
和protected
。如果您希望将域类从基础结构中分离出来,那么您应该创建不同的项目。如果你想把域分成几个部分,使用EntityFramework搜索BoundedContext策略。
回到你的问题,在你目前的情况下,我认为解决这个问题最简单的方法是创建一个新属性:
public static Expression<Func<Trainer, IEnumerable<ICollection<TrainingClass>>>> TrainingCoursesWithClasses
{
get { return t => t._trainingCourses.Select(i => i.TrainingClasses); }
}
未测试的代码,但如果你当前的代码可以工作,这应该也可以工作。
另外,要注意:
public IEnumerable<TrainingCourse> TrainingCourses
{
get
{
return _trainingCourses
.Where(tc => tc.IsActive)
.AsEnumerable();
}
}
这可能会生成IEnumerable的多个枚举。如果你想每次获得属性时只获得"IsActive == true",你应该创建一个DbCommandTreeInterceptor
。
此外,没有理由将集合设为"私有"并创建返回该集合的公共表达式;没有任何理由。可以使用:
轻松访问该集合var traininCoursesLambda = Trainer.TrainingCourses;
var trainingCourses = traininCoursesLambda.Compile().Invoke(trainer);
希望有帮助!