C# 如何整合表达式<;Func<&燃气轮机&燃气轮机;清理我的Linq到实体查询?

C# 如何整合表达式<;Func<&燃气轮机&燃气轮机;清理我的Linq到实体查询?,c#,asp.net,linq,entity-framework,linq-to-sql,C#,Asp.net,Linq,Entity Framework,Linq To Sql,我想使用Expression方法来清理我的DTO Linq to Query Selects,这样就不会使它们比现有的增长更多。对于如何将它们集成到我自己的项目中,我仍然有点困惑 例如: public IQueryable<ExampleDTO> SelectDTO() { var repository = new ExampleUDCRepository(); return db.Example .Select(v => new Example

我想使用
Expression
方法来清理我的DTO Linq to Query Selects,这样就不会使它们比现有的增长更多。对于如何将它们集成到我自己的项目中,我仍然有点困惑

例如:

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
                             })
           });
public IQueryable SelectDTO()
{
var repository=newexampleudcrespository();
返回db.Example
.选择(v=>newexampledto
{
ExampleID=v.ExampleID,
MasterGroupID=v.MasterGroupID,
//…等等
ExampleUDCs=db.ExampleUDCs
.Where(vudc=>vudc.ExampleID==v.ExampleID)
.可计算的()
.选择(vudc=>new ExampleDCDTO
{
ExampleID=vudc.ExampleID,
UDCHeadingID=vudc.UDCHeadingID,
UDCValue=vudc.UDCValue
})
});
我的其他一些DTO设置和返回方法甚至更大、更草率

我真正想做的是这样的事情:

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
           });
public IQueryable SelectDTO()
{
var repository=newexampleudcrespository();
返回db.Example
.选择(v=>newexampledto
{
ExampleID=v.ExampleID,
MasterGroupID=v.MasterGroupID,
//…等等
ExampleUDCs=新建ExampleUDCsRepository()。选择DTO(v);
//选择存储库中的DTO(示例v)将调用
//它可能需要的任何其他选择,等等
});
问题是,Linq不知道如何将这样的方法转换成SQL语句,这就是
Expression
方法用来传递此类内容的地方

我对
Expression
的理解是有限的,而且我还没有找到任何文档可以让我想做的更清楚


表达式
集成到我的DTO中的最佳方法是什么?

因此,首先我们需要一些辅助方法。我们将从这个简单的类开始,用另一个表达式替换一个表达式的所有实例:

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);
    }
}
接下来,我们将创建一个扩展方法来使用它:

public static Expression Replace(this Expression expression,
    Expression searchEx, Expression replaceEx)
{
    return new ReplaceVisitor(searchEx, replaceEx).Visit(expression);
}
最后,我们将创建一个将两个表达式组合在一起的
Combine
方法。它将使用一个表达式从一个值计算中间结果,然后使用第一个值和中间结果来确定最终结果

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);
}
现在,我们可以调用此
SelectDTO
方法来生成计算中间值的表达式,并
将它与使用它的另一个表达式组合起来:

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

这是一个有趣且描述得很好的问题,但在粘贴代码时请格外小心。IDE的标签转换为4*空格,在第一次“粘贴”时并不总是真正可读。我对其进行了一点修剪,没有进行任何实际更改,而且不会像之前那样伤害眼睛。但是,当然,与所有化妆品一样,这只是我的个人操作inion和small suggestion;)我唯一的另一个问题是那里的.Invoke()方法。我的SelectDTO(在第一个方法中被调用的一个)是否需要更改?例如
表达式SelectDTO(示例五)
?我无法让该实现按您的方式工作。说Invoke()具有无效的参数。Thanks@nzondlo然后不要使用LINQKit解决方案,使用其他解决方案。
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,
                }));
}
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),
            });
}