2012-08-06 77 views
1

方案与列工作:NHibernate的,通过反射

我有一个处理表的寻呼/排序/搜索,与服务器端钩JavaScript库。我已经连接了服务器端的JSON调用,创建了一个模型绑定器,它将传入的值转换为可用的请求对象,并且正在尝试执行搜索。

通过请求对象,我可以访问要排序的列的列表。我试图编写一个通用函数,允许任何表在其列中传递,并生成.Where调用每列和搜索值。

此时的方法是取字符串属性名称,使用反射来获取实际值,然后将其与搜索参数进行比较。该非常粗糙的方法我想是:

public static IQueryable GetSearchClause(IQueryable<object> query, DataTablesPageRequest pageRequest) 
{ 
    var columns = pageRequest.ColumnNames.Split(','); 

    for (var i = 0; i < pageRequest.Searchable.Count; ++i) 
    { 
     if (pageRequest.Searchable[i]) 
     { 
      var column = columns[i]; 

      var test = query.Where(x => x.GetType().GetProperty(column) 
       .GetValue(query.Select(z => z.GetType()), null) 
       .Equals("test")); 
     } 
    } 

    return query; 
} 

当我看看所产生的“测试”对象,我得到一个非常不愉快的堆栈跟踪:

at NHibernate.Linq.Visitors.HqlGeneratorExpressionTreeVisitor.VisitMethodCallExpression(MethodCallExpression expression) 
    at NHibernate.Linq.Visitors.HqlGeneratorExpressionTreeVisitor.VisitExpression(Expression expression) 
    at NHibernate.Linq.Visitors.HqlGeneratorExpressionTreeVisitor.Visit(Expression expression, VisitorParameters parameters) 
    at NHibernate.Linq.Visitors.QueryModelVisitor.VisitWhereClause(WhereClause whereClause, QueryModel queryModel, Int32 index) 
    at Remotion.Linq.Clauses.WhereClause.Accept(IQueryModelVisitor visitor, QueryModel queryModel, Int32 index) 
    at Remotion.Linq.QueryModelVisitorBase.VisitBodyClauses(ObservableCollection`1 bodyClauses, QueryModel queryModel) 
    at Remotion.Linq.QueryModelVisitorBase.VisitQueryModel(QueryModel queryModel) 
    at NHibernate.Linq.Visitors.QueryModelVisitor.Visit() 
    at NHibernate.Linq.Visitors.QueryModelVisitor.GenerateHqlQuery(QueryModel queryModel, VisitorParameters parameters, Boolean root) 
    at NHibernate.Linq.NhLinqExpression.Translate(ISessionFactoryImplementor sessionFactory) 
    at NHibernate.Hql.Ast.ANTLR.ASTQueryTranslatorFactory.CreateQueryTranslators(String queryIdentifier, IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 filters, ISessionFactoryImplementor factory) 
    at NHibernate.Engine.Query.HQLExpressionQueryPlan.CreateTranslators(String expressionStr, IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory) 
    at NHibernate.Engine.Query.HQLExpressionQueryPlan..ctor(String expressionStr, IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory) 
    at NHibernate.Engine.Query.HQLExpressionQueryPlan..ctor(String expressionStr, IQueryExpression queryExpression, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory) 
    at NHibernate.Engine.Query.QueryPlanCache.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow, IDictionary`2 enabledFilters) 
    at NHibernate.Impl.AbstractSessionImpl.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow) 
    at NHibernate.Impl.AbstractSessionImpl.CreateQuery(IQueryExpression queryExpression) 
    at NHibernate.Linq.DefaultQueryProvider.PrepareQuery(Expression expression, IQuery& query, NhLinqExpression& nhQuery) 
    at NHibernate.Linq.DefaultQueryProvider.Execute(Expression expression) 
    at NHibernate.Linq.DefaultQueryProvider.Execute[TResult](Expression expression) 
    at Remotion.Linq.QueryableBase`1.GetEnumerator() 
    at System.Linq.SystemCore_EnumerableDebugView`1.get_Items() 

我能做到,甚至我试图用这种技术,还是应该真正使用每个实体的方法,因为我会提前知道要搜索哪些列(并跳过整个反射位)?

+3

你能使用ICriteria吗?那么你不需要任何反射,只需使用属性名称即可。 – dotjoe 2012-08-06 14:47:59

+0

尚未使用IC标准 - 但看起来更容易一些。我会稍微想一下。既然你问我是否可以使用它...有什么理由我不想使用它?对于您在NH中编写查询的方式,我仍然有点困惑;比另一个更受欢迎? – heyseuss 2012-08-06 14:54:02

+0

只是不同的工具...我总是使用QueryOver(建立在ICriteria之上),因为它具有最多的NH功能。我问的唯一理由是如果有人玩政治,只让你使用linq(IQueryable)接口。 – dotjoe 2012-08-06 15:38:06

回答

1

任务完成!在我的基础知识库中创建了所有知识库都是从这个知识库继承而来,目前它已经足够用于跨多个实体,但我相信我会在将来遇到问题。这里唯一真正有趣的事情是,我希望子列被命名为“parent.child”,这是我在DataTables列命名中强制执行的约定。

public ICriteriaWrapper GetWithPagingSortingFiltering(
    Type entityType, 
    string columnNames, 
    List<bool> searchableColumns, 
    string searchParameter, 
    int numSortingColumns, 
    List<int> sortingColumns, 
    List<string> sortingDirection, 
    int currentPage, 
    int itemsPerPage) 
{ 
    // Create the criteria for the given entity type 
    var crit = _session.CreateCriteria(entityType); 

    // Split the columns, which will be used as our properties 
    var columns = columnNames.Split(','); 

    // Add criteria for searchable columns, so long as a parameter is given 
    if (searchParameter != string.Empty) 
    { 
     var disjunction = Restrictions.Disjunction(); 

     for (var i = 0; i < searchableColumns.Count; ++i) 
     { 
      if (searchableColumns[i]) 
      { 
       var column = columns[i]; 
       var columnParts = column.Split('.'); 

       // Handles immediate children only 
       if (columnParts.Count() == 2) 
       { 
        var child = columnParts[0]; 
        var aliasName = "the" + child; 
        var propertyName = aliasName + "." + columnParts[1]; 

        crit.CreateAlias(child, aliasName); 

        disjunction.Add(
         Restrictions.Like(
          Projections.Cast(NHibernateUtil.AnsiString, Projections.Property(propertyName)), 
          searchParameter, MatchMode.Start)); 
       } 
       // Handles base level properties 
       else if (columnParts.Count() == 1) 
       { 
        disjunction.Add(
         Restrictions.Like(
          Projections.Cast(NHibernateUtil.AnsiString, Projections.Property(column)), 
          searchParameter, MatchMode.Start)); 
       } 
       else 
       { 
        throw new Exception("Unrecognized number of children; add more conditionals!"); 
       } 
      } 
     } 

     crit.Add(disjunction); 
    } 

    // Grab the total items count 
    var totalItemsCrit = CriteriaTransformer.Clone(crit); 
    var totalItems = totalItemsCrit.SetProjection(Projections.RowCount()).UniqueResult(); 

    // Apply ordering 
    for (var i = 0; i < numSortingColumns; ++i) 
    { 
     var direction = sortingDirection[i]; 
     var column = columns[sortingColumns[i]]; 

     if (direction == "asc") 
      crit.AddOrder(Order.Asc(column)); 
     else if (direction == "desc") 
      crit.AddOrder(Order.Desc(column)); 
    } 

    // Apply paging 
    var startPage = (itemsPerPage == 0 
         ? 1 
         : currentPage/itemsPerPage + 1); 

    crit.SetFirstResult(startPage).SetMaxResults(itemsPerPage); 

    return new ICriteriaWrapper 
     { 
      Criteria = crit, 
      TotalItems = Convert.ToInt32(totalItems) 
     }; 
}