NHibernateで使用するために、リストアイテムのプロパティで並べ替える動的linqを記述しようとしています
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)
IEnumerable <T>での動的LINQ OrderByの答えに似たアプローチをとった
しかし、その後、再帰でドリルダウンしました
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クラスに存在しないことです。
私が達成しようとしていることは可能ですか?
これで何か助けていただければ幸いです。
NHibernateには、これに適した他のクエリAPIがあります。
string property = "Employees.PayrollNo";
var query = session.QueryOver<Company>()
.Fetch(x => x.Employees).Eager;
// Join on the associations involved
var parts = property.Split('.');
var criteria = query.UnderlyingCriteria;
for (int i = 0; i < parts.Length - 1; i++)
{
criteria.CreateAlias(parts[i], parts[i]);
}
// add the order
criteria.AddOrder(new Order(property, !isDescending));
var companies = query.List();