目前在我的MVC网格中,我使用普通的服务器绑定,然后将过滤器作为查询字符串附加到URL。这种方法的问题是,如果我查询默认情况下有数千条记录的网格,但我只在网格的第一页(分页过滤器)上显示前30条记录。同样的事情适用于姓氏的字符串过滤器。我过滤我的2000条记录的姓氏史密斯,得到100条记录,只有30条显示在第一页。然后,我将实际查询一个人对象,返回完整的2k对象,将其过滤为100,然后显示30.这非常低效。
如何将过滤器参数传递给LINQ查询,例如初始查询只返回该页面上显示的结果?还有一些自动化方法可以为任何网格一般地执行此操作吗?或者你必须为你拥有的每个网格编写这个逻辑吗?
我知道ToGridModel
是否在将网格导出为excel时使用:
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时。我必须重新查询整个结果集,然后将其过滤掉。
当然有更好的方法吗?
答案 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();
}
}