Telerik MVC Extensions Grid - 如何让网格过滤器应用于初始LINQ查询或传递给db?

时间:2014-10-27 17:43:35

标签: c# asp.net-mvc telerik telerik-grid telerik-mvc

目前在我的MVC网格中,我使用普通的服务器绑定,然后将过滤器作为查询字符串附加到URL。这种方法的问题是,如果我查询默认情况下有数千条记录的网格,但我只在网格的第一页(分页过滤器)上显示前30条记录。同样的事情适用于姓氏的字符串过滤器。我过滤我的2000条记录的姓氏史密斯,得到100条记录,只有30条显示在第一页。然后,我将实际查询一个人对象,返回完整的2k对象,将其过滤为100,然后显示30​​.这非常低效。

如何将过滤器参数传递给LINQ查询,例如初始查询只返回该页面上显示的结果?还有一些自动化方法可以为任何网格一般地执行此操作吗?或者你必须为你拥有的每个网格编写这个逻辑吗?

我知道ToGridModel是否在将网格导出为ex​​cel时使用:

 public ActionResult Export(int page, string orderBy, string filter, string groupBy)
    {
        //Get the data representing the current grid state - page, sort and filter
        List<Building> buildings = _buildingService.GetList();
        List<BuildingModel> buildingModels = new List<BuildingModel>();

        buildings.ForEach(x => buildingModels.Add(_buildingService.ConvertToModel(x)));

        GridModel model = buildingModels.AsQueryable().ToGridModel(1, buildingModels.Count, orderBy, groupBy, filter);

        MemoryStream fileOutput = ExcelUtil.ExportGridModelToExcel<BuildingModel>(model);

        return File(fileOutput.ToArray(),   //The binary data of the XLS file
            "application/vnd.ms-excel", //MIME type of Excel files
            "BuildingsReport.xls");     //Suggested file name in the "Save as" dialog which will be displayed to the end user
    }

但我想另一个问题是网格本身是由ViewModels组成的,而不是POCO对象。即便如此,当我导出到excel时。我必须重新查询整个结果集,然后将其过滤掉。

当然有更好的方法吗?

3 个答案:

答案 0 :(得分:2)

您可以使用自定义绑定来执行此操作。

您可以在此处阅读的简单示例:Telerik Documentation

对于更通用的方法,您可以使用类CreateFilterExpression

的方法FilterDescriptor

<强>更新

通用示例:

[GridAction(EnableCustomBinding = true)]
public ViewResult GetRecords(GridCommand command)
{
    using (var context = _contextFactory())
    {
        var records = context.Set<Records>();
        if (command.FilterDescriptors.Any())    //RequestNumber
        {                    
            var filter = command.FilterDescriptors.GetFilter<ChangeRecord>();
            records = records.Where(filter);
        }
        return View(new GridModel(records.ToArray()));
    }
}

public static class GridCommandExtensions
{
    public static Expression<Func<TGridModel, bool>> GetFilter<TGridModel>(this IList<IFilterDescriptor> filterDescriptors)
    {
        var filters = filterDescriptors.SelectMany(GetAllFilterDescriptors).ToArray();
        var parameter = Expression.Parameter(typeof(TGridModel), "c");
        if (filters.Length == 1)
            return Expression.Lambda<Func<TGridModel, bool>>(GetExpression(parameter, filters[0]), parameter);

        Expression exp = null;
        for (int index = 0; index < filters.Length; index += 2)   // условие И
        {
            var filter1 = filters[index];

            if (index == filters.Length - 1)
            {
                exp = Expression.AndAlso(exp, GetExpression(parameter, filter1));
                break;
            }
            var filter2 = filters[index + 1];
            var left = GetExpression(parameter, filter1);
            var right = GetExpression(parameter, filter2);
            exp = exp == null
                ? Expression.AndAlso(left, right)
                : Expression.AndAlso(exp, Expression.AndAlso(left, right));
        }

        return Expression.Lambda<Func<TGridModel, bool>>(exp, parameter);
    }
    private static Expression GetExpression(ParameterExpression parameter, FilterDescriptor filter)
    {
        var containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
        var startsWithMethod = typeof(string).GetMethod("StartsWith", new[] { typeof(string) });
        var endsWithMethod = typeof(string).GetMethod("EndsWith", new[] { typeof(string) });

        var property = filter.Member.Contains(".") ?
            filter.Member.Split('.').Aggregate((Expression)parameter, Expression.Property)  // (x => x.Property.FieldName)
            : Expression.Property(parameter, filter.Member);                                // (x => x.FieldName)
        var constant = Expression.Constant(filter.Value);               // значение для выражения

        switch (filter.Operator)
        {
            case FilterOperator.IsEqualTo:
                return Expression.Equal(property, constant);
            case FilterOperator.IsNotEqualTo:
                return Expression.NotEqual(property, constant);

            case FilterOperator.Contains:
                return Expression.Call(property, containsMethod, constant);
            case FilterOperator.StartsWith:
                return Expression.Call(property, startsWithMethod, constant);
            case FilterOperator.EndsWith:
                return Expression.Call(property, endsWithMethod, constant);

            case FilterOperator.IsGreaterThan:
                return Expression.GreaterThan(property, constant);
            case FilterOperator.IsGreaterThanOrEqualTo:
                return Expression.GreaterThanOrEqual(property, constant);
            case FilterOperator.IsLessThan:
                return Expression.LessThan(property, constant);
            case FilterOperator.IsLessThanOrEqualTo:
                return Expression.LessThanOrEqual(property, constant);
            default:
                throw new InvalidOperationException(string.Format("Неподдерживаемая операция {0} для колонки {1}", filter.Operator, filter.Member));
        }
    }
    public static IEnumerable<FilterDescriptor> GetAllFilterDescriptors(this IFilterDescriptor descriptor)
    {
        var filterDescriptor = descriptor as FilterDescriptor;
        if (filterDescriptor != null)
        {
            yield return filterDescriptor;
            yield break;
        }

        var compositeFilterDescriptor = descriptor as CompositeFilterDescriptor;
        if (compositeFilterDescriptor != null)
        {
            if (compositeFilterDescriptor.LogicalOperator == FilterCompositionLogicalOperator.Or)
                throw new ArgumentOutOfRangeException("descriptor", "В фильтрах не поддерживается OR");

            foreach (var childDescriptor in compositeFilterDescriptor.FilterDescriptors.SelectMany(GetAllFilterDescriptors))
                yield return childDescriptor;
        }
    }
 }

答案 1 :(得分:0)

我更喜欢使用

IEnumerable<Building> buildings = _buildingService.GetIEnumerable().AsQueryable().ToGridModel(page, pageSize, orderBy, string.Empty, filter).Data.Cast<Building>();

答案 2 :(得分:0)

        if(request.Filters.Count > 0)
        {

            foreach (Kendo.Mvc.FilterDescriptor f in request.Filters)
            {
                f.Value = f.Value.ToString().Trim();
            }
        }