Entity framework 使用OrElse和AndAlso表达式方法的异常
我正在尝试以编程方式构建表达式树 我的输入中有一个条件类列表,其形式如下:Entity framework 使用OrElse和AndAlso表达式方法的异常,entity-framework,linq,linq-to-entities,linq-expressions,dynamic-linq,Entity Framework,Linq,Linq To Entities,Linq Expressions,Dynamic Linq,我正在尝试以编程方式构建表达式树 我的输入中有一个条件类列表,其形式如下: public class Filter { public string field { get; set; } public string operator { get; set; } public string value { get; set; } } 当我构建表达式对象时,我用以下方式为每个条件创建一个表达式 foreach ( Filter sf in rules ) { Exp
public class Filter
{
public string field { get; set; }
public string operator { get; set; }
public string value { get; set; }
}
当我构建表达式
对象时,我用以下方式为每个条件创建一个表达式
foreach ( Filter sf in rules ) {
Expression ex = sf.ToExpression( query );
if ( mainExpression == null ) {
mainExpression = ex;
}
else {
if ( logicalCondition == "AND" ) {
mainExpression = Expression.And( mainExpression, ex );
}
else if ( logicalCondition == "OR" ) {
mainExpression = Expression.Or( mainExpression, ex );
}
}
}
Filter.ToExpression()方法的实现方式如下
public override Expression ToExpression( IQueryable query ) {
ParameterExpression parameter = Expression.Parameter( query.ElementType, "p" );
MemberExpression memberAccess = null;
foreach ( var property in field.Split( '.' ) )
memberAccess = MemberExpression.Property( memberAccess ?? ( parameter as Expression ), property );
ConstantExpression filter = Expression.Constant( Convert.ChangeType( value, memberAccess.Type ) );
WhereOperation condition = (WhereOperation)StringEnum.Parse( typeof( WhereOperation ), operator );
LambdaExpression lambda = BuildLambdaExpression( memberAccess, filter, parameter, condition, value );
return lambda;
}
当我有一个单一条件时,一切都正常,但当我尝试使用和
、或
、和以及或lse
静态方法之一组合表达式时,我收到一个invalidooperation异常
,它表示:
未为类型定义二进制运算符或
'System.Func2[MyObject,System.Boolean]'和
'System.Func
2[MyObject,System.Boolean]'
我有点糊涂了。有人能更好地解释异常的原因并提出解决方案吗
非常感谢 你把a=>a==3
和a=>a==4
组合成(a=>a==3)| |(a=>a==4)
,但是你应该试着把它变成a=>(a==3 | | a==4)
。这不是很难手动完成,但是。寻找“组合表达式”
编辑:根据要求,提供了一个如何手动执行此操作的简单示例
编辑2:它使用.NET 4中新增的ExpressionVisitor
,但是。我假设MSDN代码不符合您的“第三方”要求。您只需将受保护的虚拟表达式访问(Expression exp)
方法更改为public
。由于Enumerable.Zip对您不可用,并且不需要,因此它现在已不存在
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
namespace DemoApp
{
<include ExpressionVisitor definition here for .NET 3.5>
public class ExpressionParameterReplacer : ExpressionVisitor
{
public ExpressionParameterReplacer(IList<ParameterExpression> fromParameters, IList<ParameterExpression> toParameters)
{
ParameterReplacements = new Dictionary<ParameterExpression, ParameterExpression>();
for (int i = 0; i != fromParameters.Count && i != toParameters.Count; i++)
ParameterReplacements.Add(fromParameters[i], toParameters[i]);
}
private IDictionary<ParameterExpression, ParameterExpression> ParameterReplacements
{
get;
set;
}
protected override Expression VisitParameter(ParameterExpression node)
{
ParameterExpression replacement;
if (ParameterReplacements.TryGetValue(node, out replacement))
node = replacement;
return base.VisitParameter(node);
}
}
class Program
{
static void Main(string[] args)
{
Expression<Func<int, bool>> exprA = a => a == 3;
Expression<Func<int, bool>> exprB = b => b == 4;
Expression<Func<int, bool>> exprC =
Expression.Lambda<Func<int, bool>>(
Expression.OrElse(
exprA.Body,
new ExpressionParameterReplacer(exprB.Parameters, exprA.Parameters).Visit(exprB.Body)),
exprA.Parameters);
Console.WriteLine(exprA.ToString());
Console.WriteLine(exprB.ToString());
Console.WriteLine(exprC.ToString());
Func<int, bool> funcA = exprA.Compile();
Func<int, bool> funcB = exprB.Compile();
Func<int, bool> funcC = exprC.Compile();
Debug.Assert(funcA(3) && !funcA(4) && !funcA(5));
Debug.Assert(!funcB(3) && funcB(4) && !funcB(5));
Debug.Assert(funcC(3) && funcC(4) && !funcC(5));
}
}
}
使用系统;
使用System.Collections.Generic;
使用系统诊断;
使用System.Linq;
使用System.Linq.Expressions;
命名空间DemoApp
{
公共类ExpressionParameterReplace:ExpressionVisitor
{
公共表达式参数替换器(IList fromParameters,IList TopParameters)
{
ParameterReplacements=新字典();
for(int i=0;i!=fromParameters.Count&&i!=toParameters.Count;i++)
参数替换。添加(从参数[i],到参数[i]);
}
私人索引参数替换
{
得到;
设置
}
受保护的重写表达式VisitParameter(ParameterExpression节点)
{
参数表达替换;
if(ParameterReplacements.TryGetValue(节点,输出替换))
节点=替换;
返回基本访问参数(节点);
}
}
班级计划
{
静态void Main(字符串[]参数)
{
表达式exprA=a=>a==3;
表达式exprB=b=>b==4;
表达式表达式表达式=
Lambda(
奥莱尔斯酒店(
exprA.Body,
新表达式参数replacer(exprB.Parameters,exprA.Parameters)。访问(exprB.Body)),
表达式参数);
Console.WriteLine(exprA.ToString());
Console.WriteLine(exprB.ToString());
Console.WriteLine(exprC.ToString());
Func funcA=exprA.Compile();
Func funcB=exprB.Compile();
Func Func=exprC.Compile();
Assert(funcA(3)&&!funcA(4)&!funcA(5));
Assert(!funcB(3)&funcB(4)&funcB(5));
Assert(funcC(3)&&funcC(4)&&funcC(5));
}
}
}
您好,谢谢您的回答。我不能用第三方代码来解决这个问题。你能更好地解释一下哪种方法是“手工操作”吗?再次感谢@Lorenzo当然,我已经添加了一个基于我用作示例的两个表达式的程序。嗨,我已经尝试实现了你的解决方案。我知道ExpressionVisitor来自LinqKit的源代码,我已经了解了它的工作原理。现在的问题是:IEnumerable
的Zip
方法从何而来?我正在使用.NET 3.5,但找不到该方法:(@Lorenzo啊,我用的是.NET4,它同时带有ExpressionVisitor
类和Enumerable.Zip
扩展方法。我会看看我是否也能为3.5版做些工作,但那会有点复杂。@Lorenzo事实证明,MS在MSDN上发布了一个功能性ExpressionVisitor
,所以我测试了它。)看看它是否有效(它确实有效),并提到它。而且Enumerable.Zip实际上不是必需的,所以我放弃了它,在它的位置添加了一个简单的for
循环。