c# - Telerik MVC Extensions Grid - 如何将网格过滤器应用于初始 LINQ 查询或传递到数据库?

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

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

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

我知道我在将网格导出到 Excel 时使用的 ToGridModel:

 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
    }

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

肯定有更好的方法吗?

最佳答案

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

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

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

更新

通用示例:

[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;
        }
    }
 }

关于c# - Telerik MVC Extensions Grid - 如何将网格过滤器应用于初始 LINQ 查询或传递到数据库?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26593552/

相关文章:

c# - 为什么 ForEach 方法只适用于列表

c# - ItemsControl 仅显示 namespace.class,不呈现 DataTemplate

javascript - 如何使用 JavaScript 确认对话框菜单触发表单提交事件

c# - 拖放到 radTreeListView 中

c# - 在主线程继续任务

asp.net-mvc - ASP.Net MVC 3 哪些文件夹是网络可见的

asp.net-mvc - 为什么ASP.NET MVC Html.CheckBox输出两个具有相同名称的INPUT?

asp.net - Telerik-Grid:除了 HeaderStyle-CssClass 之外还启用皮肤类名

c# - 在整个星期的网格行中显示星期几数值

c# - 返回(类型)实例或返回实例作为类型