Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/294.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 构建LINQ表达式以在SQL输出中转换为括号_C#_Sql_Linq_Entity Framework - Fatal编程技术网

C# 构建LINQ表达式以在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 =

我使用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 = 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));
}