1

シナリオ:

サーバー側のフックを使用して、テーブルのページング/並べ替え/検索を処理する 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()

この手法で私がやろうとしていることを達成することさえできますか、それとも実際にエンティティごとのアプローチを使用する必要がありますか?

4

1 に答える 1

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)
        };
}
于 2012-08-06T20:51:27.703 に答える