如何整合前pression<&Func键LT;>>清理我的LINQ到实体的查询? [英] How do I integrate Expression<Func<>> to clean up my Linq-to-Entity queries?

查看:161
本文介绍了如何整合前pression<&Func键LT;>>清理我的LINQ到实体的查询?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用防爆pression< Func键<>> 方法来清理我的DTO LINQ到查询选择,以免使他们比他们已经长大了。我还是有点困惑,如何将其融入我自己的项目。

I want to use the Expression<Func<>> method to clean up my DTO Linq-to-Query Selects so as not to make them grow anymore than what they already have. I'm still a little confused as to how to integrate them into my own project.

一个例子:

public IQueryable<ExampleDTO> SelectDTO()
{
  var repository = new ExampleUDCRepository();

  return db.Example
           .Select(v => new ExampleDTO
           {
             ExampleID     = v.ExampleID,
             MasterGroupID = v.MasterGroupID,
             //...etc

             ExampleUDCs = db.ExampleUDCs
                             .Where(vudc => vudc.ExampleID == v.ExampleID)
                             .AsEnumerable()
                             .Select(vudc => new ExampleDCDTO
                             {
                               ExampleID    = vudc.ExampleID,
                               UDCHeadingID = vudc.UDCHeadingID,
                               UDCValue     = vudc.UDCValue
                             })
           });

我的一些其他DTO设置和回报方式有更大,更模糊。

Some of my other DTO setup and return methods are even bigger and sloppier.

我真正想要做的是这样的:

What I really want to do is something like this:

public IQueryable<ExampleDTO> SelectDTO()
{
  var repository = new ExampleUDCRepository();

  return db.Example
           .Select(v => new ExampleDTO
           {
             ExampleID     = v.ExampleID,
             MasterGroupID = v.MasterGroupID,
             //...etc

             ExampleUDCs = new ExampleUDCsRepository().SelectDTO(v);
             // SelectDTO(Example v) in that repository would call
             // any other SelectDTO it might need and so forth
           });

问题是,LINQ的不知道怎么样的方法转换为SQL语句,这哪里是防爆pression&LT; Func键&LT;&GT;&GT; 方法已经开始发挥作用了绕过这种事。

Problem is, Linq doesn't know how to convert methods like that into an SQL statement, which is where the Expression<Func<>> method has come into play for passing around this sort of thing.

我的理解防爆pression&LT; Func键&LT;&GT;&GT; 是有限的,我还没有发现有任何文件还使我什么试图做更清晰。

My understanding of Expression<Func<>> is limited and I haven't found any documentation out there yet that makes what I'm trying to do much clearer.

什么是整合的最佳方式防爆pression&LT; Func键&LT;&GT;&GT; 进入我的DTO这样

What is the best way of integrating Expression<Func<>> into my DTO like this?

推荐答案

所以,首先我们需要一些辅助方法。我们将开始与这个简单的类与另一个替换一个EX pression的所有实例:

So first off we'll need a few helper methods. We'll start off with this simple class to replace all instances of one expression with another:

internal class ReplaceVisitor : ExpressionVisitor
{
    private readonly Expression from, to;
    public ReplaceVisitor(Expression from, Expression to)
    {
        this.from = from;
        this.to = to;
    }
    public override Expression Visit(Expression node)
    {
        return node == from ? to : base.Visit(node);
    }
}

接下来,我们将创建一个扩展的方法来使用它:

Next we'll create an extension method to use it:

public static Expression Replace(this Expression expression,
    Expression searchEx, Expression replaceEx)
{
    return new ReplaceVisitor(searchEx, replaceEx).Visit(expression);
}

最后,我们将创建一个联合方法,将两位前pressions结合在了一起。它会采取一前pression从一个值计算的中间结果,然后再同时使用所述第一值和所述中间结果,以确定最终的结果。

Finally, we'll create a Combine method that will combine two expressions together. It will take one expression that computes an intermediate result from a value, and then another that uses both the first value and the intermediate result to determine the final result.

public static Expression<Func<TFirstParam, TResult>>
    Combine<TFirstParam, TIntermediate, TResult>(
    this Expression<Func<TFirstParam, TIntermediate>> first,
    Expression<Func<TFirstParam, TIntermediate, TResult>> second)
{
    var param = Expression.Parameter(typeof(TFirstParam), "param");

    var newFirst = first.Body.Replace(first.Parameters[0], param);
    var newSecond = second.Body.Replace(second.Parameters[0], param)
        .Replace(second.Parameters[1], newFirst);

    return Expression.Lambda<Func<TFirstParam, TResult>>(newSecond, param);
}

接下来,我们可以定义计算给定的示例对象的ExampleDCDTO对象方法。这将是你在上面有什么直接提取,所不同的是,而不是返回一个的IEnumerable&LT; ExampleDCDTO&GT; 它会需要返回一个前pression了打开一个示例进入这样一个序列:

Next we can define the method that computes the ExampleDCDTO objects given an example object. It will be a straight extraction of what you had above, with the exception that instead of returning an IEnumerable<ExampleDCDTO> it'll need to return an expression that turns an Example into such a sequence:

public Expression<Func<Example, IEnumerable<ExampleDCDTO>>> SelectDTO()
{
    return v => db.ExampleUDCs.Where(vudc => vudc.ExampleID == v.ExampleID)
        .AsEnumerable()
        .Select(vudc => new ExampleDCDTO
        {
            ExampleID = vudc.ExampleID,
            UDCHeadingID = vudc.UDCHeadingID,
            UDCValue = vudc.UDCValue
        });
}

现在把它放在一起,我们可以调用这个 SelectDTO 方法生成的前pression,计算中间值和联合它使用它的另一位前pression:

Now to bring it all together we can call this SelectDTO method to generate the expression that computes the intermediate value and Combine it with another expression that uses it:

public IQueryable<ExampleDTO> SelectDTO()
{
    ExampleUDCRepository repository = new ExampleUDCRepository();
    return db.Example
            .Select(repository.SelectDTO().Combine((v, exampleUDCs) =>
                new ExampleDTO()
                {
                    ExampleID = v.ExampleID,
                    MasterGroupID = v.MasterGroupID,
                    ExampleUDCs = exampleUDCs,
                }));
}

另一种选择,对于使用这些 LINQKit ,就是用 AsExpandable ,而不是我所有的辅助方法。使用这种方法仍然需要创建返回防爆pression&LT的 SelectDTO 方法; Func键&lt;例,IEnumerable的&LT; ExampleDCDTO&GT;&GT;&GT; ,但是你不是合并的结果,像这样:

Another option, for those using LINQKit, is to use AsExpandable instead of all of my helper methods. Using this approach would still require creating the SelectDTO method that return an Expression<Func<Example, IEnumerable<ExampleDCDTO>>>, but you would instead combine the result like so:

public IQueryable<ExampleDTO> SelectDTO()
{
    ExampleUDCRepository repository = new ExampleUDCRepository();
    var generateUDCExpression = repository.SelectDTO();
    return db.Example
        .AsExpandable()
        .Select(v =>
            new ExampleDTO()
            {
                ExampleID = v.ExampleID,
                MasterGroupID = v.MasterGroupID,
                ExampleUDCs = generateUDCExpression.Invoke(v),
            });
}

这篇关于如何整合前pression&LT;&Func键LT;&GT;&GT;清理我的LINQ到实体的查询?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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