Запрос nhibernate, как с деревьями выражений - PullRequest
7 голосов
/ 17 января 2012

Я хочу добавить метод в свой базовый класс репозитория, который позволит мне использовать выражения LIKE , но я не совсем уверен, как это сделать. Я хочу создать универсальный метод, который просматривает переданное дерево выражений и ищет подстановочные знаки в передаваемых строковых значениях. Затем он сгенерирует соответствующий оператор QueryOver.

В настоящее время у меня есть следующее:

public IList<T> FindAll(Expression<Func<T, bool>> criteria, char wildCard)
{
    return SessionFactory.GetCurrentSession()
            .QueryOver<T>()
            .Where(criteria)
            .List();
}

Очевидно, что трудная часть еще впереди. Мне нужно просмотреть дерево выражений и построить запрос, используя QueryOver динамически. Ищите несколько советов о том, как поступить с этим. Или я просто трачу свое время здесь и должен просто создать отдельные методы в своих репозиториях, которые обрабатывают запросы LIKE ?

Дополнительные критерии

В идеале я бы хотел сказать разницу между:

  • Поиск *
  • * Поиск
  • * Поиск *

Таким образом, сгенерированный запрос будет:

  • поле LIKE 'search%'
  • поле LIKE '% search'
  • поле LIKE '% search%'

Ответы [ 3 ]

13 голосов
/ 17 января 2012

Есть два способа написать выражение Like в QueryOver.

Если вы сделаете это из предложения Where:

.Where(Restrictions.Like(Projections.Property<T>(*projected property*), *string value*, MatchMode.Anywhere))

Однако это довольно долго писать.

Таким образом, вы можете использовать WhereRestrictionOn:

.WhereRestrictionOn(*projected property*).IsLike(*string value*, MatchMode.Anywhere)

Это означает, что вам нужно передать два параметра, таких как:

FindAll<User>(x => x.FirstName, "bob");

Вы можете использовать .Contains, .StartsWith,.Заканчивается, но я не уверен.

FindAll<User>(x => x.FirstName.Contains("bob"));
FindAll<User>(x => x.FirstName.StartsWith("bob"));
FindAll<User>(x => x.FirstName.EndsWith("bob"));

Я не думаю, что они работают в NHibernate.

Надеюсь, это поможет.

0 голосов
/ 12 ноября 2014

Поработав некоторое время для решения проблемы перевода выражений вида

session.QueryOver<T>().Where(x => x.StringAttrbute.StartsWith("ajoofa"))

в SQL вида

SELECT * FROM {table} WHERE {string_attribute} LIKE 'ajoofa%'

, я нашел следующее решение: Ю нужно зарегистрировать вызовы пользовательских методов для стандартных строковых функций .Contains (), .StartsWith, .EndsWith ().Бог знает, почему эти функции не зарегистрированы по умолчанию в NHibernate.Следующий код должен помочь вам.

/// Perform the registration of custom methods
/// </summary>
public static void Register()
{
    if (!_registered)
    {
    _registered = true;
    String str = null;
    ExpressionProcessor.RegisterCustomMethodCall(() => str.StartsWith(null), ProcessStartsWith);
    ExpressionProcessor.RegisterCustomMethodCall(() => str.EndsWith(null), ProcessEndsWith);
    ExpressionProcessor.RegisterCustomMethodCall(() => str.Contains(null), ProcessContains);
    }
}

static ICriterion ProcessStartsWith(MethodCallExpression methodCallExpression)
{
    ExpressionProcessor.ProjectionInfo projection = ExpressionProcessor.FindMemberProjection(methodCallExpression.Object);
    object value = ExpressionProcessor.FindValue(methodCallExpression.Arguments[0]) + "%";
    return projection.CreateCriterion(Restrictions.Like, Restrictions.Like, value);
}

static ICriterion ProcessEndsWith(MethodCallExpression methodCallExpression)
{
    ExpressionProcessor.ProjectionInfo projection = ExpressionProcessor.FindMemberProjection(methodCallExpression.Object);
    object value = "%" + ExpressionProcessor.FindValue(methodCallExpression.Arguments[0]);
    return projection.CreateCriterion(Restrictions.Like, Restrictions.Like, value);
}

static ICriterion ProcessContains(MethodCallExpression methodCallExpression)
{
    ExpressionProcessor.ProjectionInfo projection = ExpressionProcessor.FindMemberProjection(methodCallExpression.Object);
    object value = "%" + ExpressionProcessor.FindValue(methodCallExpression.Arguments[0]) + "%";
    return projection.CreateCriterion(Restrictions.Like, Restrictions.Like, value);
}
0 голосов
/ 17 января 2012

Я не очень понимаю, что вы хотите сделать.Хотите, чтобы запрос, такой как

session.QueryOver<T>().Where(x => x.property == "*substring*").List();

, генерировал свойство LIKE "% substring%" запрос?В большинстве провайдеров Linq метод String.Contains преобразуется в запрос «LIKE», и, таким образом, вам не нужно искать символы подстановки в дереве выражений, только для метода String.Contains.
В случаеВо-вторых, вам придется анализировать дерево выражений в поисках метода String.Contains ().Это может быть очень хлопотно (http://msdn.microsoft.com/en-us/library/bb397951.aspx). Кроме того, я не вижу в вашем методе, какое свойство нужно «сравнивать» с оператором LIKE.

В любом случае, я думаю, что было бы легче передать критерий ICriterion.к вашему .Where (), например

.Where(new NHibernate.Criterion.LikeExpression("property", "%value%"))

, и сразу после этого добавьте другие условия с помощью .And (). Недостатком является потеря строго типизированных запросов.

...