C# 构建LINQ表达式以在SQL输出中转换为括号
我使用EntityFramework6和在运行时添加表达式,效果非常好 然而,我无法解决的是如何用SQL中的括号分隔表达式的各个部分 例如:C# 构建LINQ表达式以在SQL输出中转换为括号,c#,sql,linq,entity-framework,C#,Sql,Linq,Entity Framework,我使用EntityFramework6和在运行时添加表达式,效果非常好 然而,我无法解决的是如何用SQL中的括号分隔表达式的各个部分 例如: SELECT * FROM SOMETABLE WHERE Field1 = 'somevalue' AND (FIELD2 = 1 OR FIELD2 = 2 OR FIELD2 = 3) 而不是 SELECT * FROM SOMETABLE WHERE Field1 = 'somevalue' AND FIELD2 = 1 OR FIELD2 =
SELECT * FROM SOMETABLE WHERE Field1 = 'somevalue' AND (FIELD2 = 1 OR FIELD2 = 2 OR FIELD2 = 3)
而不是
SELECT * FROM SOMETABLE WHERE Field1 = 'somevalue' AND FIELD2 = 1 OR FIELD2 = 2 OR FIELD2 = 3
这将输出不同的结果,并且在第二种情况下是错误的
我真正想要的例子
虽然在SQL中,我会使用in子句来执行OR部分
通常我只是在过滤器的相关部分加上括号,但在运行时,我不知道传入值列表时需要多少个OR语句,这些值的数量只有在运行时才知道,即:
public Search(IList<int> vals, string filter){
Expression<Func<Event, bool>> filter = x => x.Field1 == filter;
bool first = true;
for(int i in vals){
if (first){
filter = filter.And(x -> x.Field2 == i);
first = false;
}
else{
filter = filter.Or(x -> x.Field2 == i);
}
}
}
有人知道如何使用表达式实现这一点吗?您应该在和语句之前创建或语句:
public Search(IList<int> vals, string filter){
Expression<Func<Event, bool>> andFilter = x => x.Field1 == filter;
var firstVal = vals.First();
Expression<Func<Event, bool>> orFilter = x=>x.Field2 == firstVal;
foreach(int i in vals.Skip(1)){
orFilter = orFilter.Or(x -> x.Field2 == i);
}
andFilter = andFilter.And(orFilter);
}
好的,所以我不得不从侧面思考来解决这个问题,因为我找不到一种使用表达式生成器的方法,可能还有一种方法 相反,我转向我发现的罗斯林 使用Rosyln,您可以将字符串编译成C代码并返回输出,以便在运行时进一步使用 因此,我现在不再附加表达式,而是将表达式创建为字符串中的一段代码,使用Rosyln编译它,然后返回用于过滤数据的新表达式 这就是它的工作原理:
ScriptEngine scriptEngine = new ScriptEngine();
string exp = "public System.Linq.Expressions.Expression<System.Func<my.namespace.object,bool>> CreateFilter(){System.Linq.Expressions.Expression<System.Func<my.namespace.object,bool>> filter = e => e.Field1.Contains(\"a\");return filter;}CreateFilter();";
与任何其他项目一样,您需要添加对代码所需的任何非系统程序集的引用
最后,您只需执行返回新表达式的代码
使用此技术,您可以轻松地添加任何您喜欢的括号,并使用循环和其他条件语句构建表达式
我在NuGet上找到了Roslyn。很抱歉我在这方面回复晚了。 这是我的解决方案代码
// at this point query will be: SELECT * FROM SOMTABLE WHERE Field1 = 'Cat'
Expression<Func<Event, bool>> filterExpression = x => x.Field1 == filter;
if (vals.Count > 0)
{
// at this point query will be: SELECT * FROM SOMTABLE WHERE Field1 = 'Cat' AND Field2 = 1
filterExpression = filterExpression.And(x => x.Field2 == vals.First());
}
if (vals.Count > 1)
{
// at this point query will be: SELECT * FROM SOMTABLE WHERE Field1 = 'Cat' AND (Field2 = 1 OR Field2 = 3 OR Field2 = 4)
filterExpression = filterExpression.Or(x => vals.Skip(1).Contains(x.Field2));
}
我在这里发布了一个vs解决方案的链接:为什么不能使用vals.Containsx.Field2?这不是更容易吗?它应该自动生成您的或声明。我认为这行不通,Andrey。contains语句列表仍然会生成单独的OR语句,这些语句不会作为一个逻辑部分运行,这正是我所需要的。它只是重新排列SQL,但没有括号,以使每个部分按正确的顺序求值,即像BODMAS语句一样,它不会工作。
Expression<Func<Event, bool>> filter = (Expression<Func<Event, bool>>)s.Execute(exp);
// at this point query will be: SELECT * FROM SOMTABLE WHERE Field1 = 'Cat'
Expression<Func<Event, bool>> filterExpression = x => x.Field1 == filter;
if (vals.Count > 0)
{
// at this point query will be: SELECT * FROM SOMTABLE WHERE Field1 = 'Cat' AND Field2 = 1
filterExpression = filterExpression.And(x => x.Field2 == vals.First());
}
if (vals.Count > 1)
{
// at this point query will be: SELECT * FROM SOMTABLE WHERE Field1 = 'Cat' AND (Field2 = 1 OR Field2 = 3 OR Field2 = 4)
filterExpression = filterExpression.Or(x => vals.Skip(1).Contains(x.Field2));
}