【发布时间】:2015-01-09 16:26:07
【问题描述】:
我正在尝试编写一些动态 linq 来按列表项的属性排序,以便与 NHibernate 一起使用
public class Company
{
public string Name { get; set; }
public List<Employee> Employees { get; set; }
}
public class Employee
{
public string Name{get; set;}
public string PayrollNo{get; set;}
}
在此示例中,它希望返回所有公司并按 PayrollNumber 排序。
使用标准 linq 的存储库方法看起来像这样。
var companies = session.Query<Company>()
.OrderBy(x => x.Pieces.FirstOrDefault().PayrollNo)
.FetchMany(x => x.Employees)
我想将此更改为动态 linq 以按列标题排序
var companies = session.Query<Company>()
.OrderByName("Employees.PayrollNo"), isDescending)
.FetchMany(x => x.Employees)
我采取了类似于Dynamic LINQ OrderBy on IEnumerable<T>Writing an extension method中答案的方法
然后用递归向下钻取
public static IQueryable<T> OrderByName<T>(this IQueryable<T> source, string propertyName, Boolean isDescending)
{
if (source == null) throw new ArgumentNullException("source");
if (propertyName == null) throw new ArgumentNullException("propertyName");
var properties = propertyName.Split('.');
var type = GetNestedProperty(properties, typeof(T));
var arg = Expression.Parameter(type.GetProperty(properties.Last()).PropertyType, "x");
var expr = Expression.Property(arg, properties.Last());
Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), type);
LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg);
String methodName = isDescending ? "OrderByDescending" : "OrderBy";
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 (IQueryable<T>)result;
}
//Walk the tree of properties looking for the most nested in the string provided
static Type GetNestedProperty(string[] propertyChain, Type type)
{
if (propertyChain.Count() == 0)
return type;
string first = propertyChain.First();
propertyChain = propertyChain.Skip(1).ToArray(); //strip off first element
//We hare at the end of the hierarchy
if (propertyChain.Count() == 0)
return GetNestedProperty(propertyChain, type);
//Is Enumerable
if (type.GetProperty(first).PropertyType.GetInterfaces().Any(t => t.Name == "IEnumerable"))
return GetNestedProperty(
propertyChain,
type.GetProperty(first).PropertyType.GetGenericArguments()[0]);
return GetNestedProperty(
propertyChain,
type.GetProperty(first).PropertyType.GetProperty(propertyChain.FirstOrDefault()).GetType());
}
我很难在 OrderByName 扩展方法中生成表达式。我现在已经尝试了很多东西,但问题是 Company 类中不存在 Payroll number。
我正在努力实现的目标是否可能?
对此的任何帮助将不胜感激。
【问题讨论】:
-
您的动态方法最终需要具备静态方法所需的所有功能。您的静态方法有一个
First调用。如果您希望它以相同的方式运行,这显然也需要在您的动态方法中。 -
感谢Servy,这当然是有道理的。我只写了静态 linq 来解释这个问题,我一直在想我正在尝试生成 .OrderBy(x => x.Pieces.PayrollNo)
-
鉴于这不会静态工作,显然在动态生成它时也不会工作。这就是为什么您应该始终有一个静态示例来说明您尝试动态创建的内容,并且您需要确保您的动态解决方案与该特定情况相匹配。显然你的不匹配。
-
感谢Servy,现在看来很明显了。我会将表达式构建移动到递归方法中并让它在今天工作。
标签: c# .net linq nhibernate dynamic-linq