4

我有一个标准的 ASP.NET MVC 3 控制器,其操作具有以下签名: public ActionResult Index(int? page, string sort, string sortDir) 我的视图正在使用 WebGrid,因此它会自动生成参数。

接下来我使用动态表达式 API(又名动态 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();

目标

我想做的是使用动态表达式 API本身来验证用于排序的参数(并可能创建一个有效的 lambda)。例如,我想使用DynamicExpression.Parse()orDynamicExpression.ParseLambda()方法来查看它们是否产生ParseException,在这种情况下,我可以用默认值替换错误的参数(例如按名称升序“名称 ASC”排序)...

问题

问题是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"); 

回顾

我想使用动态 LINQ 来 1)验证和 2)基于操作参数构建谓词(用于排序)

4

1 回答 1

0

我对 Dymaic LINQ 不是很熟悉,但您可以执行以下操作:

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:如果您决定保留 LINQ,请尝试以下签名 -OrderBy("Name", "ascending");

UPD2:如果你想验证你的排序参数,我认为,反射是唯一的选择。像这样的东西:

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

这样一来,您应该仅在为真时应用OrderBy/OrderByDescending逻辑。doSort否则,只需跳过排序或应用任何默认逻辑。

在我看来,你想要的代码功能越多,适合它的 LINQ 似乎就越少。一旦PropertyInfo获得,下一个合理的步骤可能是在表达中使用它。一旦我们这样做了,哪里会是 LINQ 的地方?:)

我同意表达式和反射代码在操作中非常难看,但是将其移到外部,例如,在我的情况下,到 ExtensionMethod,或者在控制器基类的 NonAction 方法中,可以避免你看到它:)

于 2012-04-09T16:48:14.203 回答