使用EF6,如何将给定的Expression<Func<Row, string>>
参数绑定到现有的select表达式,而不必使用表达式树重写每个属性绑定?
public IEnumerable<RowModel> GetRowModels(Expression<Func<Row, string>> textExpr)
{
return from row in MyDatabaseContext.MyTable
select new RowModel
{
RowID = row.ID,
CreatedDate = row.CreatedDate,
AnotherProperty = row.AnotherProperty,
Text = textExpr, // how do I bind this expression?
Value = row.OtherStuff.Where(os => os.ShouldUse).Select(os => os.Value).FirstOrDefault(),
AnotherValue = row.OtherStuff.Where(os => os.ShouldUseAgain).Select(os => os.Value).FirstOrDefault()
};
}
答案 0 :(得分:2)
这里需要的是一种组合多个表达式的方法。具体来说,我们想要的是一种方法来获取映射值的表达式,然后接受接受第一个表达式的输入和第一个表达式的输出的表达式,并计算新值。
作为这种方法的一种实现,我们可以替换第一个函数的结果&#34;&#34;与第一个功能的身体;之后,所有需要做的就是确保两个表达式都使用相同的Parameter
实例。
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);
}
以下代码用于将表达式的所有实例替换为另一个:
public static Expression Replace(this Expression expression,
Expression searchEx, Expression replaceEx)
{
return new ReplaceVisitor(searchEx, replaceEx).Visit(expression);
}
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);
}
}
至于使用功能;它很简单。我们在Combine
上调用textExpression
,然后我们可以创建一个lambda,接受第一个表达式的行和文本结果作为参数。这使您可以编写一个几乎与您已有的lambda一样的lambda,但是您可以使用text参数来分配Text
值:
public IEnumerable<RowModel> GetRowModels(
Expression<Func<Row, string>> textExpr)
{
return MyDatabaseContext.MyTable.Select(
textExpr.Combine((row, text) => new RowModel
{
RowID = row.ID,
CreatedDate = row.CreatedDate,
AnotherProperty = row.AnotherProperty,
Text = text, // how do I bind this expression?
Value = row.OtherStuff.Where(os => os.ShouldUse)
.Select(os => os.Value).FirstOrDefault(),
AnotherValue = row.OtherStuff.Where(os => os.ShouldUseAgain)
.Select(os => os.Value).FirstOrDefault()
}));
}