我有一个这样的给定linq-sql:
var erg = from p in m_session.Query<LovTestData>()
select new
{
SomeString = p.SomeString,
SomeOtherString = p.SomeOtherString
};
这应该是“爱”对话框的“基础”查询。因此,这是定义Lov内容的查询。
但是LOV中有要搜索的字段。因此,这是我在运行时用来填充“爱”的查询:
var erg = from p in m_session.Query<LovTestData>()
where ((string.IsNullOrEmpty(someStringValueFilter) || p.SomeString.ToLower().Contains(someStringValueFilter.ToLower())) &&
(string.IsNullOrEmpty(someOtherStringFilter) || p.SomeOtherString.ToLower().Contains(someOtherStringFilter.ToLower())))
select new
{
SomeString = p.SomeString,
SomeOtherString = p.SomeOtherString
};
所以我想知道之后如何将where子句“注入”给定查询?我认为这应该是这样的:
var erg = from p in m_session.Query<LovTestData>()
select new
{
SomeString = p.SomeString,
SomeOtherString = p.SomeOtherString
};
var additionalWhere = ... //Some way to define this part: ((string.IsNullOrEmpty(someStringValueFilter) || p.SomeString.ToLower().Contains(someStringValueFilter.ToLower())) && (string.IsNullOrEmpty(someOtherStringFilter) || p.SomeOtherString.ToLower().Contains(someOtherStringFilter.ToLower())))
erg = InjectWhere(erg, additionalWhere); //In this function the where is inserted into the linq so the result is the second query.
已更新:
additionalWhere应该从原始查询中构造出来。因此,我无法编写“ p.SomeString”,因为extraWhere的构造是通用的。这是我获取字段的方式
Type elementType = erg.ElementType;
foreach (PropertyInfo pi in elementType.GetProperties())
{
//pi.name...
}
答案 0 :(得分:0)
如果Query返回IQueryable,则完全没有问题。
List<LovTestData> GetTestData(Expression<Func<T, bool>> where)
{
var erg = from p in m_session.Query<LovTestData>()
select new
{
...
}
IQueryable result = erg.Where(where);
return result.ToList();
}
现在。 IQueryable不会执行您真正使用它的单元。因此,您可以选择,在何处进行合并等操作,但是在使用IQueryable之前,它什么也不会做。真正的SQL将在以下位置运行:result.ToList()。这就是为什么您可以更早地建立所有条件的原因。当然,假设m_session.Query返回IQueryable,但据我所知-确实如此。
因此,您甚至可以在没有我创建的结果变量的情况下执行此操作。只需对erg进行操作即可。
Waayd的评论也将起作用。
好,现在要动态创建过滤器。 让我们上一个简单的课:
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
现在,让我们创建一个记录列表-数据库。
List<Person> list = new List<Person>
{
new Person {Name = "Adam Abc", Age = 15},
new Person {Name = "John Abc", Age = 23},
new Person {Name = "Steven Abc", Age = 26},
new Person {Name = "Adam Bca", Age = 21},
new Person {Name = "Adam Xyz", Age = 26},
};
现在,让我们准备一个过滤器。您必须从视图中获取过滤器数据,现在让我们模拟一下:
string nameIs = "Adam";
bool createAgeFilter = true;
int ageFilterMin = 20;
int ageFilterMax = 25;
所以我们需要所有年龄在20到25岁之间的亚当。让我们创建这个条件:
姓名的第一个条件:
Func<Person, bool> whereName = new Func<Person, bool>((p) =>
{
if (!string.IsNullOrWhiteSpace(nameIs))
return p.Name.Contains(nameIs);
else
return true;
}
);
年龄的下一个条件:
Func<Person, bool> whereAge = new Func<Person, bool>((p) =>
{
if (createAgeFilter)
return p.Age >= ageFilterMin && p.Age <= ageFilterMax;
else
return true;
}
);
接下来,让我们使用IQueryable:
IQueryable<Person> q = list.AsQueryable();
最后,我们添加where子句:
List<Person> filteredList = q.Where(whereName)
.Where(whereAge)
.ToList();
就是这样。其背后的想法是,您必须创建几个部分where子句。每个要过滤的东西。但是我最后所做的将使过滤器之间的“与”。如果您想对其进行“或”操作,则应使用另一种过滤器类型-类似于年龄过滤器。
我刚刚想到了这个主意。因此,可能会有更好的解决方案。甚至连一个班轮都可以。
修改 如果您不能像这样使用linq,那么还有另一种方法。但不是那么简单。 您的应用程序中一定有一点要以LINQ样式构建过滤器。例如,在您看来。因此,采用此表达式并调用ToString()。您将获得linq查询的字符串表示形式。
接下来要做的是安装Roslyn软件包。 最后,您可以使用Roslyn魔术将LINQ表达式的字符串表示形式更改为LINQ表达式:
public async static Task<Expression<Func<T, bool>>> ExpressionFromStr<T>(string expressionStr)
{
var options = ScriptOptions.Default.AddReferences(typeof(T).Assembly);
return await CSharpScript.EvaluateAsync<Expression<Func<T, bool>>>(expressionStr, options);
}
用途:
using Microsoft.CodeAnalysis.CSharp.Scripting; //roslyn
using Microsoft.CodeAnalysis.Scripting; //roslyn
using System;
using System.Linq.Expressions;
using System.Threading.Tasks; //for async and Task.