C# 在表达式树中使用局部变量
我有一个LINQ表达式,用于查找给定客户信用余额的所有历史变化:C# 在表达式树中使用局部变量,c#,linq,entity-framework-5,expression-trees,C#,Linq,Entity Framework 5,Expression Trees,我有一个LINQ表达式,用于查找给定客户信用余额的所有历史变化: var history = GetHistory(id); var changes = history.Where(x => history.Where(y => y.AuditId < x.AuditId) .OrderByDescending(y => y.AuditId)
var history = GetHistory(id);
var changes = history.Where(x => history.Where(y => y.AuditId < x.AuditId)
.OrderByDescending(y => y.AuditId)
.Select(y => y.CreditBalance)
.FirstOrDefault() != x.CreditBalance);
var history=GetHistory(id);
var changes=历史记录。其中(x=>history.Where(y=>y.auditdy.D)
.选择(y=>y.CreditBalance)
.FirstOrDefault()!=x.CreditBalance);
此函数按预期工作。我想做的是更改此函数,以允许用户查询对任何历史字段的更改。我选择的解决方法是使用表达式树
到目前为止,我已经提出了以下解决方案:
var history = GetHistory(id);
var c = Expression.Parameter(typeof(Customer_history), "c");
var d = Expression.Parameter(typeof(Customer_history), "d");
var cAudit = Expression.Property(c, typeof(Customer_history).GetProperty("AuditId"));
var dAudit = Expression.Property(d, typeof(Customer_history).GetProperty("AuditId"));
var whereBody = Expression.LessThan(dAudit, cAudit);
var whereLambda = Expression.Lambda(whereBody, d);
var where = Methods.QueryableWhere.MakeGenericMethod(typeof(Customer_history));
var whereCall = Expression.Call(null, where, **Expression.Constant(history)**, whereLambda);
var orderByLambda = Expression.Lambda(dAudit, d);
var orderBy = Methods.QueryableOrderByDescending.MakeGenericMethod(typeof(Customer_history), orderByLambda.Body.Type);
var orderByCall = Expression.Call(null, orderBy, whereCall, orderByLambda);
var dProp = Expression.Property(d, typeof(Customer_history).GetProperty(field));
var selectLambda = Expression.Lambda(dProp, d);
var select = Methods.QueryableSelect.MakeGenericMethod(typeof(Customer_history), selectLambda.Body.Type);
var selectCall = Expression.Call(null, select, orderByCall, selectLambda);
var firstOrDefault = Methods.QueryableFirstOrDefault.MakeGenericMethod(selectLambda.Body.Type);
var firstOrDefaultCall = Expression.Call(null, firstOrDefault, selectCall);
var cProp = Expression.Property(c, typeof(Customer_history).GetProperty(field));
var comparison = Expression.NotEqual(firstOrDefaultCall, cProp);
var lambda = Expression.Lambda<Func<Customer_history, bool>>(comparison, c);
var changes = history.Where(lambda);
var history=GetHistory(id);
var c=表达式参数(类型(客户历史记录),“c”);
var d=表达式参数(typeof(Customer_history),“d”);
var cAudit=Expression.Property(c,typeof(Customer_history).GetProperty(“audit”);
var dAudit=Expression.Property(d,typeof(Customer_history).GetProperty(“audit”);
var whereBody=表达式.LessThan(dAudit,cAudit);
var whereLambda=表达式.Lambda(whereBody,d);
var where=Methods.QueryableWhere.MakeGenericMethod(typeof(Customer_history));
var whereCall=Expression.Call(null,其中,**Expression.Constant(history)**,whereLambda);
var orderByLambda=表达式.Lambda(dAudit,d);
var orderBy=Methods.QueryableOrderByDescending.MakeGenericMethod(typeof(Customer_history),orderbyrambda.Body.Type);
var orderByCall=Expression.Call(null,orderBy,whereCall,orderByLambda);
var dProp=Expression.Property(d,typeof(Customer_history).GetProperty(field));
var selectLambda=Expression.Lambda(dProp,d);
var select=Methods.QueryableSelect.MakeGenericMethod(typeof(Customer\u history),selectLambda.Body.Type);
var selectCall=Expression.Call(null、select、orderByCall、selectLambda);
var firstOrDefault=Methods.QueryableFirstOrDefault.MakeGenericMethod(selectLambda.Body.Type);
var firstOrDefaultCall=Expression.Call(null,firstOrDefault,selectCall);
var cProp=Expression.Property(c,typeof(Customer_history).GetProperty(field));
var比较=Expression.NotEqual(firstOrDefaultCall,cProp);
var lambda=表达式.lambda(比较,c);
var变化=历史。其中(λ);
问题是,我在执行查询时遇到了以下异常:
无法创建类型为的常量值
“名称空间。客户历史记录”。只有基元类型或枚举
在此上下文中支持类型
现在我假设问题是基于异常消息的Expression.Constant(history)语句。问题是,我不知道如何重写它以允许查询提供者适当地处理它。我知道这是因为原始查询的缘故,我只是不知道如何在表达式树中实现它
有人能提供任何方向吗?正如人们所怀疑的那样,恒常表达式似乎不是从局部变量获取值的方法 我需要做的是创建一个私有类来存储变量,然后我就可以使用FieldMemberExpression访问它
private class ValueHolder<T>
{
public IQueryable<T> History;
}
私人类价值持有人
{
公众可阅读的历史;
}
然后,在我的方法中,我能够使用以下公式计算表达式:
var valueHolder = new ValueHolder<T>
{
History = data
};
var c = Expression.Parameter(typeof(T), "c");
var constantEx = Expression.Constant(valueHolder);
var fieldEx = Expression.Field(constantEx, valueHolder.GetType().GetField("History"));
var值持有人=新的值持有人
{
历史=数据
};
var c=表达式参数(类型(T),“c”);
var constantEx=表达式常数(valueHolder);
var fieldEx=Expression.Field(constantEx,valueHolder.GetType().GetField(“历史”));
您可以尝试使用动态linq,它允许您使用字符串作为表达式,而不是lambda
例如:
var query = history.Where("MyField = MyFilter");
如何允许您从条件访问局部变量?