我正在使用linq来nhibernate来搜索实体名称及其别名。
class Entity
{
string Name { get; set; }
string[] Aliases { get; set; }
}
enityQueryable.Where(x =>
x.Name.StartsWith(searchParam) ||
x.Aliases.Any(a => a.StartsWith(searchParam)));
那部分工作正常。
我现在要求匹配可能的搜索字词列表。我可以在linq中进行查询,但是正如预期的那样,Nhibernate无法将其转换为Hql。
enityQueryable.Where(x => MatchOnNameOrAlias(x));
private bool MatchOnNameOrAlias(Entity e, string[] searchTerms)
{
foreach (var searchTerm in searchTerms)
{
if (e.Name.StartsWith(searchTerm))
{
return true;
}
if (e.Aliases.Any(a => a.StartsWith(companySearchTerm)))
{
return true;
}
}
return false;
}
我开始考虑使用LinqToHqlGenerator
,实施是相对直接的,并且在第一次检查时似乎有效但是它只在第一次工作。后续调用会重复使用相同的搜索参数集合。
public class MatchesAnySearchTermGenerator : BaseHqlGeneratorForMethod
{
public MatchesAnySearchTermGenerator()
{
SupportedMethods = new[] { ReflectionHelper.GetMethod(() => SearchLinqExtensions.MatchesAnySearchTerm(null, null)) };
}
public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor)
{
var likes = ((IEnumerable<string>)((ConstantExpression) arguments[1]).Value).ToArray();
HqlBooleanExpression lastBooleanExpression = CreateHqlLike(treeBuilder, visitor.Visit(arguments[0]).AsExpression(), likes[0]);
for (int i = 1; i < likes.Length; i++)
{
lastBooleanExpression = treeBuilder.BooleanOr(lastBooleanExpression,
CreateHqlLike(treeBuilder, visitor.Visit(arguments[0]).AsExpression(), likes[i]));
}
return lastBooleanExpression;
}
private HqlLike CreateHqlLike(HqlTreeBuilder treeBuilder, HqlExpression nameExpression, string like)
{
return treeBuilder.Like(nameExpression, treeBuilder.Constant(like + '%'));
}
}
这似乎是一个已知问题。
因此,无需直接使用NHibernate来执行查询并在我的代码库中维护对IQueryable的依赖。是否有Nhibernate支持的第一个查询的替代方法,或者我是否可以构造HqlGenerator以使其不会缓存第一个搜索项列表?
答案 0 :(得分:0)
我有一个满足我需求的解决方案。它不使用Hql Generator方法。相反,它构建了linq查询,以便Nhibernate可以将其转换为Hql本身。以下链接有助于此,第二个实际上是第一个如果您阅读评论的改进。
NHibernate Linq provider: dynamic filtering using lambda expressions
Dynamically built LINQ query no longer working in NH3.0
我能够做到以下几点:
Expression<Func<Entity, bool>> predicate = null;
predicate = searchTerms.Aggregate(predicate, (current, source1) => current == null ? NameStartsWith(source1) : current.Or(NameStartsWith(source1)));
enityQueryable.Where(predicate);
private static Expression<Func<Entity, bool>> NameStartsWith(string searchTerm)
{
return p => p.Name.ToLower().StartsWith(searchTerm) || p.Aliases.Any(x => x.StartsWith(searchTerm));
}
使用两个链接中提到的方法:
static class PredicateBuilder
{
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
{
var adaptedExpr2Body = ReplacingExpressionTreeVisitor.Replace(
expr2.Parameters[0],
expr1.Parameters[0],
expr2.Body);
return Expression.Lambda<Func<T, bool>>(
Expression.AndAlso(expr1.Body, adaptedExpr2Body),
expr1.Parameters);
}
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
{
var adaptedExpr2Body = ReplacingExpressionTreeVisitor.Replace(
expr2.Parameters[0],
expr1.Parameters[0],
expr2.Body);
return Expression.Lambda<Func<T, bool>>(
Expression.OrElse(expr1.Body, adaptedExpr2Body),
expr1.Parameters);
}
}