如何将一个附加的where子句“注入”到给定的nHibernate linq中?

时间:2019-01-11 09:56:13

标签: c# linq nhibernate

我有一个这样的给定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...
}

1 个答案:

答案 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.