Как «вставить» дополнительное предложение where в данный nHibernate linq? - PullRequest
0 голосов
/ 11 января 2019

У меня есть заданный linq-sql, как это:

var erg = from p in m_session.Query<LovTestData>()
          select new
          {
              SomeString = p.SomeString,
              SomeOtherString = p.SomeOtherString
          };

Это должен быть "базовый" -запрос для Lov-Dialog. Так что это запрос, который определяет содержание Lov.

Но в 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.

Изменено:

ДополнительныеWhere должны быть построены из исходного запроса. Поэтому я не могу написать «p.SomeString», потому что конструкция дополнительного Where универсальна. Так я получаю поля

Type elementType = erg.ElementType;
foreach (PropertyInfo pi in elementType.GetProperties())    
{
    //pi.name...
}

1 Ответ

0 голосов
/ 11 января 2019

Если 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 НЕ ИСПОЛНИТЕ, если вы действительно используете его. Таким образом, вы можете выбрать select, where, union и так далее, но пока вы не используете IQueryable, он ничего не будет делать. Здесь будет работать настоящий SQL: result.ToList (). Вот почему вы можете построить все там условия раньше. Конечно, предполагая, что m_session.Query возвращает IQueryable, но, насколько я помню, это так.

Так что вы можете даже сделать это без созданной мной переменной результата. Просто оперируй эрг.

Комментарий Ваайда также будет работать.

Хорошо, теперь о динамическом создании фильтра. Давайте возьмем простой класс:

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. Наконец, вы можете изменить строковое представление выражения LINQ на выражение LINQ, используя магию Roslyn:

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);
}

Usings:

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.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...