【问题标题】:Pass Lambda expression to generic repository将 Lambda 表达式传递给通用存储库
【发布时间】:2012-11-12 10:44:47
【问题描述】:

我正在尝试将 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);
        }

【问题讨论】:

  • 抱歉,我已经更新了问题......
  • 您能否编辑您的问题并显示您用于获取相关订购的代码并致电GetAllPagingAndSorting&lt;TKey&gt;
  • @Euston 在这种情况下,您的 TKey 很可能必须实现 IComparable,因此在没有看到更多结构的情况下,我建议在字典定义中更改 Object -> IComparable,看看它是否仍然抛出错误
  • @Nicholas Butler /user1793607 - 我添加了更多代码,希望能显示我想要尝试的内容。我将如何使用 IComparable 而不是 Object?

标签: c# linq generics lambda expression


【解决方案1】:

问题在于(m=&gt;m.Id) 类型为Expresion&lt;Func&lt;MyModel, int&gt;&gt; 的表达式将自动接收到object 的附加转换以匹配Expresion&lt;Func&lt;MyModel, object&gt;&gt;。您看不到代码中的演员表,但您可以观察到它分析表达式树。

我的方法是

  • 将分页、排序等所有查询参数封装到一个类中
  • 将查询结果封装在一个类中(总记录、选中记录)

因此我的解决方案如下所示

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&lt;T&gt; 传递给函数并返回IOrderedEnumerable&lt;T&gt;。由于我们不能在涵盖不同实体的字典中拥有泛型类型,因此签名如下所示:

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

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

【讨论】:

    【解决方案2】:

    我现在正在使用此代码应用从另一个堆栈溢出 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;
            } 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-09
      • 1970-01-01
      相关资源
      最近更新 更多