0

我正在尝试将 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=>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},

            };

我应该改用一种方法吗?在任何一种情况下,我如何使用上述内容来匹配输入属性并返回具有正确类型的 Lambda 表达式?

更新:这是我在控制器中的操作......我想我会尝试在此处获取订购密钥作为 Lambda,因为我使用通用存储库......

定义的通用存储方法: IEnumerable GetAllPagingAndSorting(out int totalRecords, int pageSize, int pageIndex,Expression> orderingKey, SortDirection sortOrder, params Expression>[] 包括);

  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);
        }
4

2 回答 2

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

要处理每个实体的排序,您需要将 an 传递IEnumerable<T>给函数并返回一个IOrderedEnumerable<T>. 由于我们不能在涵盖不同实体的字典中拥有泛型类型,因此签名如下所示:

Dictionary<Type, Expression<Func<IEnumerable, IEnumerable>>>

另外定义一个方法Add<T>(Expression<Func<IEnumerable<T>, IOrderedEnumerable<T>>>)来添加到字典中,并Get()检索排序表达式。

于 2012-11-12T12:05:50.503 回答
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;
        } 
于 2012-11-14T12:49:51.707 回答