2015-02-11 79 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); 
    } 
}