4

次の署名を持つアクションを持つ標準のASP.NETMVC3コントローラーがあります。 public ActionResult Index(int? page, string sort, string sortDir) ビューはWebGridを使用しているため、パラメーターは自動的に生成されます。

次に、Dynamic Expressions API(別名Dynamic LINQ)を使用して、パラメーターをクエリに変換します。例:

var customerSummary = CustomerManager.CustomerRepository.GetQuery()
      .OrderBy(sort + " " + sortDir)
      .Select(c => new CustomerSummaryViewModel()
                  {
                      Id = c.Id,
                      Name = c.Name,
                      IsActive = c.IsActive,
                      OrderCount = c.Orders.Count
                  })
      .Skip(page.Value - 1 * 10) //10 is page size
      .Take(10)
      .ToList();

目標

私がやりたいのは、Dynamic Expressions API自体を使用して、並べ替えのパラメーターを検証することです(そして、おそらく有効なラムダを作成します)。たとえば、DynamicExpression.Parse()またはDynamicExpression.ParseLambda()メソッドを使用して、それらが生成ParseExceptionされるかどうかを確認したいと思います。その場合、誤ったパラメータをデフォルトに置き換えることができます(たとえば、「NameASC」の昇順で名前で並べ替える)...

問題

問題は、IQueryable拡張機能が文字列のみを取得することです。使用したい場合にParseLambdaそれをフィードすると、.OrderBy方向を使用できません(プロパティ名のみを取得します)。たとえば、私はこれを行うことができます:

var se = DynamicExpression.ParseLambda<Customer, string>("Name"); // now I can use  .OrderBy(se) which is same as .OrderBy(c=>c.Name)

しかし、これではありません

var se = DynamicExpression.ParseLambda<Customer, string>("Name DESC"); 

要約

Dynamic LINQを使用して、1)検証し、2)アクションパラメーターに基づいて(並べ替え用の)述語を作成したいと思います。

4

1 に答える 1

0

私はDymaicLINQにあまり詳しくありませんが、次のことができます。

var customerSummary = CustomerManager.CustomerRepository.GetQuery();

if ("desc".Equals(sortDir, StringComparison.CurrentCultureIgnoreCase))
   customerSummary = customerSummary.OrderByDescending(sort);
else
   customerSummary = customerSummary.OrderBy(sort);

var pageNumber = page.GetValueOrDefault();
if (pageNumber < 1)
   pageNumber = 1;

customerSummary = customerSummary
   .Select(c => new CustomerSummaryViewModel()
      {
         Id = c.Id,
         Name = c.Name,
         IsActive = c.IsActive,
         OrderCount = c.Orders.Count
      })
   .Skip((pageNumber - 1) * 10) 
   .Take(10)
   .ToList();

私は自分のプロジェクトで(生の式を使用したことを除いて)同様のことをしましたが、さらに進んでいます。

次のようなベースViewModelを作成しました。

class TableViewModel 
{
   public string SortColumn { get; set; }
   public bool IsAsc { get; set; }
   public int? PageNumber { get; set; }
}

そして、すべてのページング/ソート作業を行うヘルパーメソッドを作成しました。署名は次のようになります。

public static IQueryable<T> TableHelper(this IQueryable<T> source, TableViewModel model) { ... }

また、テーブルコントロールからデータを受信し、要求されたデータを返す必要がある場合、コントローラーのアクションは次のようになります。

public ActionResult Index(TableViewModel model)
{
   var data = _productRepository.AsQueryable().TableHelper(model);

   ... //Operation on data
}

ヘルパーの呼び出しの前後に、フィルタリングやsmthを自由に適用できるという一般的なこと。

とても便利です。

ViewModelを拡張する必要がある場合は、それを継承し、子モデルに新しいメンバーを追加します。

UPD: DLINQを継続する場合は、次の署名を試してください-OrderBy("Name", "ascending");

UPD2:ソートパラメータを検証したい場合は、リフレクションが唯一の選択肢だと思います。このようなもの:

bool doSort = typeof(Product).GetProperty(sort, BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy /*Or whatever flags you need*/) != null

このようにすると、 trueの場合にのみOrderBy/OrderByDescendingロジックを適用する必要doSortがあります。それ以外の場合は、並べ替えをスキップするか、デフォルトロジックを適用します。

私の意見では、コードに必要な機能が多ければ多いほど、それに適したDLINQは少なくなるようです。取得したらPropertyInfo、次の合理的なステップは、それを式で使用することです。それをしたら、DLINQの場所はどこになりますか?:)

式とリフレクションのコードはアクションでは非常に醜いことに同意しますが、たとえば、私の場合のようにExtensionMethodに移動したり、コントローラー基本クラスのNonActionメソッドで移動したりすると、目が見えなくなります:)

于 2012-04-09T16:48:14.203 に答える