我正在尝试将web网格助手与通用存储库结合使用来添加列排序。具有网格助手的视图中的动作结果具有排序列(字符串)的参数。在我的泛型方法签名中,我需要根据域模型的属性名传递一个lambda表达式(见下文)。
public IEnumerable<T>GetAllPagingAndSorting<TKey>(out int totalRecords,
int pageSize, int pageIndex, Expression<Func<T, TKey>> orderingKey,
SortDirection sortOrder,
params Expression<Func<T, object>>[] includes)
{}
例如,我想将属性名称“Name”和“string”的类型映射到m =&gt; m.Name。
我尝试使用字典,如下所示,但是在调用存储库方法时会抛出错误,因为类型现在是对象而不是int,string等....
private IDictionary<string,Expression<Func<MyModel,object>>> _orderings =
new Dictionary<string, Expression<Func<MyModel,object>>>
{
{"Id",(m=>m.Id)},
{"Name",m=>m.UserName},
{"DateRequired",m=>m.DateRequired},
{"AssignedTo",m=>m.TeamMember.MemberName},
{"RequestedBy",m=>m.RequestedBy},
};
我应该使用方法吗?在任何一种情况下,如何使用上面的内容来匹配input属性并使用正确的类型返回Lambda表达式?
更新: 这是我在控制器中的动作....以为我尝试将订购密钥作为Lambda获取,因为我使用通用存储库....
定义了通用的respoitory方法: IEnumerable GetAllPagingAndSorting(out int totalRecords,int pageSize,int pageIndex,Expression&gt; orderingKey,SortDirection sortOrder,params Expression&gt; [] includes);
public ActionResult ServerPagingAndSorting(int page = 1, string sort = "Id", string sortDir = "Ascending")
{
int totalRecords;
var viewModel =new SupportRequestsIndexVM(supportrequestRepository.GetAllPagingAndSorting(out totalRecords, PageSize,page - 1,_orderings[sort] ,GetSortDirection(sortDir),(m=>m.TeamMember)))
{PageSize = PageSize, PageNumber = page, TotalRows = totalRecords};
return View(viewModel);
}
答案 0 :(得分:1)
问题在于,(m=>m.Id)
类型Expresion<Func<MyModel, int>>
会自动收到object
的额外广告,以匹配Expresion<Func<MyModel, object>>
。您没有在代码中看到强制转换,但您可以观察它分析表达式树。
我的方法是
因此我的解决方案看起来像这样
public class QueryResult<T> {
public int TotalRecords;
public List<T> Records;
}
public QueryResult<T> GetRecords<T>(QueryParams p)
{
IEnumerable<T> q = BuildQueryWithConditions<T>(p);
var result = new QueryResult<T> { TotalRecords = q.Count() };
q = ApplySortOrder(p);
q = ApplyPaging(p);
result.Records = q.ToList();
return result;
}
ApplySortOrder是一个解释SortColumn和SortOrder的每个实体函数:
switch (p.SortColumn)
{
case "Column1":
if (desc)
queryDef = queryDef.OrderByDescending(record => record.Column1);
else
queryDef = queryDef.OrderBy(record => record.Column1);
break;
....
}
要处理每个实体的排序,您需要将IEnumerable<T>
传递给函数并返回IOrderedEnumerable<T>
。由于我们不能在涵盖不同实体的字典中使用泛型类型,因此签名如下所示:
Dictionary<Type, Expression<Func<IEnumerable, IEnumerable>>>
另外定义要添加到字典的方法Add<T>(Expression<Func<IEnumerable<T>, IOrderedEnumerable<T>>>)
,并Get()
来检索排序表达式。
答案 1 :(得分:0)
我现在正在使用此代码来应用从另一个堆栈溢出q中获取的排序。我将字符串传递给通用存储库,然后按如下方式调用此方法:
这是我的存储库方法:
public IEnumerable<T> GetAllPagingAndSorting(out int totalRecords, int pageSize, int pageIndex, string orderingKey, string sortDir, params Expression<Func<T, object>>[] includes)
{
IQueryable<T> results = Entities;
totalRecords = results.Count();
// apply any includes
if (includes != null)
{
results = includes.Aggregate(results, (current, include) => current.Include(include));
}
// apply sorting
results = GetSortDirection(sortDir) == SortDirection.Ascending ? ApplyOrder(results, orderingKey, ORDERBY) : ApplyOrder(results, orderingKey, ORDERBYDESC);
if (pageSize > 0 && pageIndex >= 0)
{
// apply paging
results = results.Skip(pageIndex * pageSize).Take(pageSize);
}
return results.ToList();
}
protected static IOrderedQueryable<T> ApplyOrder(IQueryable<T> source, string property, string methodName)
{
string[] props = property.Split('.');
Type type = typeof(T);
ParameterExpression arg = Expression.Parameter(type, "m");
Expression expr = arg;
foreach (string prop in props)
{
// use reflection (not ComponentModel) to mirror LINQ
PropertyInfo pi = type.GetProperty(prop);
expr = Expression.Property(expr, pi);
type = pi.PropertyType;
}
Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), type);
LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg);
object result = typeof(Queryable).GetMethods().Single(
method => method.Name == methodName
&& method.IsGenericMethodDefinition
&& method.GetGenericArguments().Length == 2
&& method.GetParameters().Length == 2)
.MakeGenericMethod(typeof(T), type)
.Invoke(null, new object[] { source, lambda });
return (IOrderedQueryable<T>)result;
}