2015-02-11 76 views
2

我正在使用LINQ到nhibernate来搜索实体名称及其别名。NHibernate LINQ匹配搜索值的集合

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,实施了relativly直线前进,并在第一次检查出现工作但它仅适用第一次。随后的调用重用相同的搜索参数集合。

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 + '%')); 
    } 
} 

这似乎是一个已知问题。

StackOverflow Question

NHibernate Jira Issue

所以不必恢复到直接使用NHibernate来执行查询和维护我的代码基础上的IQueryable的依赖。有没有替代我的第一个查询,Nhibernate将支持或我可以构造HqlGenerator,使它不会缓存搜索条件的第一个列表?

回答

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); 
    } 
}