Запрос 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);
}