【问题标题】:Projection of single entities in EF with extension methods使用扩展方法在 EF 中投影单个实体
【发布时间】:2016-09-20 03:53:51
【问题描述】:

我喜欢使用扩展方法将我的实体模型投影到我的视图模型中。这意味着我不会过度/不足地获取我的模型,它使代码变得美观且可读。有时投影可能包含嵌套模型是有道理的,我想在这些子投影上重用。

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

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 的回答)但是当我们使用新子句进行赋值时(例如 @987654329 @) 它不是一个表达式,所以如果我们将它捆绑在一个扩展方法下(例如Me = x.Me.ToViewModel()),我们就不能将它展平为一个表达式。

在 EF 的场景下如何分配给新对象?

有没有办法通过扩展方法转换为新对象?

完整的演示代码在这里:https://github.com/lukemcgregor/ExtensionMethodProjection

编辑:

我现在有一篇博文 (Composable Repositories - Nesting Extensions) 和 nuget package 来帮助在 linq 中嵌套扩展方法

【问题讨论】:

  • 它是否适用于您当前的代码?
  • Me = x.Me.ToViewModel() 不起作用,如果您想要一个其余工作的演示应用程序,我可以发布到 GH
  • 其实看看你的Person模型和PersonModel会有所帮助,不是完整代码,而是相关部分。
  • 有点牵强,但这行得通吗:Me = x.Friends.AsQueryable().ToViewModels().Where(n =&gt; n.Name = x.Me.Name).Single()
  • 控制台应用程序中的完整工作代码:github.com/lukemcgregor/ExtensionMethodProjection

标签: c# entity-framework expression-trees


【解决方案1】:

看看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()(profile)。这是给你的练习:) }

【讨论】:

  • 您也可以直接将此类构造转换为所需的目标表达式
  • 这看起来很棒,你提到了ReplacementInExpressionTreesAttribute,这会是什么样子?我想这是我需要写的东西?看起来这应该用在树中使用时列出的表达式替换方法调用。这正是我所追求的:)
  • 好吧,我已经构建了一些可以替换的东西,我不得不将它放入我现有的访问者中,而不是使用像 MultiParamReplaceVisitor 这样的新访问者。它适用于进行替换,但如果替换的 lambda 下有任何其他扩展方法,它会中断。我认为这可能超出了这个问题的范围,所以我会问另一个。我在这里实际所做的代码:github.com/lukemcgregor/ExtensionMethodProjection/blob/master/…
  • 已经在这里提出了关于我的特定错误的新问题:stackoverflow.com/questions/39864270/… 如果您有任何想法,将不胜感激。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-09-07
  • 2015-03-12
  • 1970-01-01
  • 2019-02-01
  • 1970-01-01
  • 2011-01-07
  • 2022-11-09
相关资源
最近更新 更多