nhibernate queryover LIKE с деревьями выражений

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

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

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

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

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

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

  • поиск*
  • *поиск
  • *поиск*

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

  • поле LIKE 'поиск%'
  • поле LIKE '%search'
  • поле LIKE '%search%'

person Cole W    schedule 17.01.2012    source источник


Ответы (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.

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

person Phill    schedule 17.01.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() сразу после этого. Недостатком является потеря строго типизированных запросов.

person Marcelo Zabani    schedule 17.01.2012
comment
Я до сих пор не знаю, используете ли вы String.Contains внутри выражения или простое равенство, чтобы сигнализировать об использовании оператора LIKE. Тем не менее, вам придется разобрать дерево выражений и интегрировать его с NHibernate с помощью комбинации .Where() и .And(). Если я что-то пропустил здесь, это определенно не стоит. Вы можете использовать несколько ограниченные запросы LIKE со строго типизированным Linq-to-NH, делая что-то вроде session.Query‹T›().Where(x =› x.property.Contains(substring)). Это, очевидно, будет искать только %substring%, что не компенсирует все ваши комбинации. - person Marcelo Zabani; 17.01.2012

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

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);
}
person Marcus    schedule 12.11.2014