我喜欢使用扩展方法从我的实体模型投影到我的视图模型中。这意味着我不会对我的模型进行过度/不足,这会使代码变得美观可读。有意义的是,有时候投影可能包含嵌套模型,我想在这些子投影上重复使用。
我希望能够执行以下操作:
ctx.People.FiltersAndThings().ToViewModels();//the project my DB Models into view models
实际投影的扩展方法
public static IQueryable<PersonModel> ToViewModels(this IQueryable<Person> entities)
{
return entities.Select(x => new PersonModel {
Me = x.Me.ToViewModel(), //this method cannot be translated into a store expression
Friends = x.Friends.AsQueryable().ToViewModels() //works fine with some magic (tm)
});
}
public static IQueryable<ProfileModel> ToViewModels(this IQueryable<Profile> entities)
{
return entities.Select(x => new ProfileModel { Name = x.Name });
}
public static ProfileModel ToViewModel(this Profile entity)
{
return new ProfileModel { Name = entity.Name };
}
当使用Queryable(例如Friends = x.Friends.AsQueryable().ToViewModels()
)时,我们可以使用一些魔法将其展平为表达式(请参阅https://stackoverflow.com/a/10726256/1070291,由@LordTerabyte回答)但是当我们使用新子句进行赋值时(例如Me = new ProfileModel { Name = x.Me.Name }
)它不是表达式,所以如果我们在扩展方法下捆绑它(例如Me = x.Me.ToViewModel()
),我们就不能将它展平为表达式。
如何在EF中的场景下对新对象进行分配?
有没有办法通过扩展方法转换为新对象?
这里有完整的演示代码:https://github.com/lukemcgregor/ExtensionMethodProjection
修改
我现在有一篇博文(Composable Repositories - Nesting Extensions)和nuget package来帮助在linq中嵌套扩展方法
答案 0 :(得分:2)
看看this answer。它的功能非常类似于你想要的东西。基本上,您将转换定义为表达式树,例如:
public static Expression<Func<Profile, ProfileModel>> ToProfileViewModel()
{
return entity => new ProfileModel { Name = entity.Name };
}
然后调用它(例如ExpressionsHelper.ToProfileViewModel()。AsQuote()(p))。
如果您愿意,可以修改访问者,以便提供更好的语法。一些事情:
[ReplacementInExpressionTrees(MethodName=nameof(ExpressionsHelper.ToProfileViewModel))]
public static ProfileModel ToViewModel(this Profile profile)
{
// this implementation is only here, so that if you call the method in a non expression tree, it will still work
return ExpressionsHelper.ToProfileViewModel().Compile()(profile); // tip: cache the compiled func!
现在您需要创建一个访问者,它检查所有方法调用,当找到具有此属性的方法时,它会将整个调用更改为ExpressionsHelper.ToProfileViewModel()。AsQuote()(配置文件)。这是你的练习:) }