Запрос nhibernate, как с деревьями выражений

Я пытаюсь добавить метод в свой базовый класс репозитория, который позволяет мне использовать выражения 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 ответа

Есть два способа написать выражение 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,.EndsWith, но я не уверен.

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

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

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

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

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

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

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

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

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

Немного покопавшись для решения проблемы перевода выражений вида

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);
}
Другие вопросы по тегам