使用扩展方法预测EF中的单个实体

时间:2016-09-20 03:53:51

标签: c# entity-framework expression-trees

我喜欢使用扩展方法从我的实体模型投影到我的视图模型中。这意味着我不会对我的模型进行过度/不足,这会使代码变得美观可读。有意义的是,有时候投影可能包含嵌套模型,我想在这些子投影上重复使用。

我希望能够执行以下操作:

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中嵌套扩展方法

1 个答案:

答案 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()(配置文件)。这是你的练习:)     }