在EF中使用扩展方法投射单个实体 [英] Projection of single entities in EF with extension methods

查看:141
本文介绍了在EF中使用扩展方法投射单个实体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我喜欢使用扩展方法从我的实体模型进行投影到我的视图模型中。这意味着我不会超过/不支持我的模型,它使代码漂亮和可读性。有意义的是,有时预测可能包括嵌套模型,我想在这些子投影上重用。



我想要做一些像下面这样的事情:

  ctx.People.FiltersAndThings()。ToViewModels(); //项目我的DB模型进入视图模型

实际投影的扩展方法

 code> public static IQueryable< PersonModel> ToViewModels(此IQueryable< Person>实体)
{
return entities.Select(x => new PersonModel {
Me = x.Me.ToViewModel(),//此方法不能翻译成一个商店表达式
Friends = x.Friends.AsQueryable()。ToViewModels()//适用于一些魔术(tm)
});
}

public static IQueryable< ProfileModel> ToViewModels(这个IQueryable< Profile>实体)
{
return entities.Select(x => new ProfileModel {Name = x.Name});
}


public static ProfileModel ToViewModel(此配置文件实体)
{
返回新的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



编辑



我现在有一个博文(可组合的存储库 - 嵌套扩展)和 nuget包帮助嵌套扩展方法在linq中

解决方案

看看这个答案。它做一个非常相似的事情你想要什么。基本上你会将转换定义为一个表达式树,例如:

  public static Expression&FunC< Profile,ProfileModel>> ToProfileViewModel()
{
return entity =>新的ProfileModel {Name = entity.Name};
}

然后调用它(例如ExpressionsHelper.ToProfileViewModel())AsQuote )(p))。



如果你愿意,你可以修改访问者,以允许更好的语法。一些沿着线:

  [ReplacementInExpressionTrees(MethodName = nameof(ExpressionsHelper.ToProfileViewModel))] 
public static ProfileModel ToViewModel (这个配置文件)
{
//这个实现只在这里,所以如果你在非表达式树中调用方法,它仍然可以工作
返回ExpressionsHelper.ToProfileViewModel()。编译()(简档); //提示:缓存编译的func!

现在,您需要创建一个访问者,检查所有方法调用,当找到一个方法时属性,它将整个调用更改为ExpressionsHelper.ToProfileViewModel()。AsQuote()(配置文件)。这是你的一个练习:)
}


I like to do projection from my entity models into my view models using extension methods. This means I dont over/under fetch for my models and it makes the code nice and readable. It makes sense that sometimes the projections may include nested models, and I want to get reuse on those sub-projections.

I want to be able to do something like the following:

ctx.People.FiltersAndThings().ToViewModels();//the project my DB Models into view models

Extension methods for actual projection

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 };
}

When using a Queryable (eg Friends = x.Friends.AsQueryable().ToViewModels()) we can use some magic to flatten this to an expression (see https://stackoverflow.com/a/10726256/1070291, answer by @LordTerabyte) But when we are doing an assignment with a new clause (eg Me = new ProfileModel { Name = x.Me.Name }) its not an expression so if we bundle this under an extension method (eg Me = x.Me.ToViewModel()) we can't flatten this to an expression.

How does an assignment to a new object work under the scenes in EF?

Is there a way to do convertion to a new object via an extension method?

Full demo code here: https://github.com/lukemcgregor/ExtensionMethodProjection

Edit:

I now have a blog post (Composable Repositories - Nesting Extensions) and nuget package to help with nesting extension methods in linq

解决方案

Take a look at this answer. It does a very similar thing what you want. Basically you would define your transformation as an Expression tree, e.g:

public static Expression<Func<Profile, ProfileModel>> ToProfileViewModel()
{
    return entity => new ProfileModel { Name = entity.Name };
}

And then do invocations of this (e.g. ExpressionsHelper.ToProfileViewModel().AsQuote()(p)).

If you prefer, you can modify the visitors, to allow a nicer syntax. Something along the lines:

[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!

Now you need to create a visitor, that checks all method calls, and when finds a method with this attribute, it changes the whole call to ExpressionsHelper.ToProfileViewModel().AsQuote()(profile). This is as an exercise for you :) }

这篇关于在EF中使用扩展方法投射单个实体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆