可重用的 LINQ 方法查询
Reusable LINQ method query
是否可以通过调用 OrderBy
和 Where
创建可重用的 LINQ
查询表达式,而不将其应用于特定的 IQueryable
?
我希望能够做这样的事情:
var data = new List<PlayerDTO>();
var builder = new Builder<PlayerDTO>();
var query = builder.GetQuery();
var results = data.AsQueryable().Provider.CreateQuery(query);
如果不向 GetQuery
方法提供 IQueryable
对象,我很难让它工作。
这是我目前的代码:
public Expression GetQuery()
{
var type = typeof(T); // T is PlayerDTO
var col = type.GetProperty(OrderBy.Column);
var orderByMethod = typeof(Queryable).GetMethods().Single(
method => method.Name == "OrderBy"
&& method.IsGenericMethodDefinition
&& method.GetGenericArguments().Length == 2
&& method.GetParameters().Length == 2);
var genericOrdebyMethod = orderByMethod.MakeGenericMethod(typeof(T), col.PropertyType);
var parameter = Expression.Parameter(typeof(T), "p"); // {p}
var property = Expression.Property(parameter, col); // {p.ID}
var lambda = Expression.Lambda<Func<T, int>>(property, parameter); // {p => p.ID}
//This list should not exist here
var tempList = new List<PlayerDTO>() { new PlayerDTO(1, "First"), new PlayerDTO(2, "Second") };
var orderByMethodExpression = Expression.Call(genericOrdebyMethod, tempList.AsQueryable().Expression, lambda); // {tempList.OrderBy(p => p.ID)}
var results = tempList.AsQueryable().Provider.CreateQuery(orderByMethodExpression);
return orderByMethodExpression;
}
相关部分是对 Expression.Call
的调用,我必须在其中提供 IQueryable
才能正常工作,但我希望能够在不指定现有 IQueryable
.
这可能吗?
编辑:
既然我想到了这一点,我实际上根本不需要这样做......将 IQueryable 作为参数发送到 GetQuery 方法是非常有意义的。不过我会继续问这个问题。
您可以将其创建为从 IQueryable 到 IOrderedQueryable 的另一个表达式,例如:
public Expression getOrderByQuery<T>(PropertyInfo col)
{
var orderByMethod = typeof(Queryable).GetMethods().Single(
method => method.Name == "OrderBy"
&& method.IsGenericMethodDefinition
&& method.GetGenericArguments().Length == 2
&& method.GetParameters().Length == 2);
var genericOrdebyMethod =
orderByMethod.MakeGenericMethod(typeof(T), col.PropertyType);
var parameter = Expression.Parameter(typeof(T), "p"); // {p}
var property = Expression.Property(parameter, col); // {p.ID}
var lambda = Expression.Lambda<Func<T, int>>(property, parameter); // {p => p.ID}
var paramList = Expression.Parameter(typeof(IQueryable<T>));
// {tempList.OrderBy(p => p.ID)}
var orderByMethodExpression = Expression.Call(genericOrdebyMethod, paramList, lambda);
return Expression.Lambda(orderByMethodExpression, paramList);
}
我这样使用它,我的列表得到排序:
var tempList = new List<PlayerDTO>()
{
new PlayerDTO(2, "First"),
new PlayerDTO(1, "Second")
};
var e = (Expression<Func<IQueryable<PlayerDTO>, IOrderedQueryable<PlayerDTO>>>)
getOrderByQuery<PlayerDTO>(typeof(PlayerDTO).GetProperty("Id"));
e.Compile().Invoke(tempList.AsQueryable()).Dump();
是否可以通过调用 OrderBy
和 Where
创建可重用的 LINQ
查询表达式,而不将其应用于特定的 IQueryable
?
我希望能够做这样的事情:
var data = new List<PlayerDTO>();
var builder = new Builder<PlayerDTO>();
var query = builder.GetQuery();
var results = data.AsQueryable().Provider.CreateQuery(query);
如果不向 GetQuery
方法提供 IQueryable
对象,我很难让它工作。
这是我目前的代码:
public Expression GetQuery()
{
var type = typeof(T); // T is PlayerDTO
var col = type.GetProperty(OrderBy.Column);
var orderByMethod = typeof(Queryable).GetMethods().Single(
method => method.Name == "OrderBy"
&& method.IsGenericMethodDefinition
&& method.GetGenericArguments().Length == 2
&& method.GetParameters().Length == 2);
var genericOrdebyMethod = orderByMethod.MakeGenericMethod(typeof(T), col.PropertyType);
var parameter = Expression.Parameter(typeof(T), "p"); // {p}
var property = Expression.Property(parameter, col); // {p.ID}
var lambda = Expression.Lambda<Func<T, int>>(property, parameter); // {p => p.ID}
//This list should not exist here
var tempList = new List<PlayerDTO>() { new PlayerDTO(1, "First"), new PlayerDTO(2, "Second") };
var orderByMethodExpression = Expression.Call(genericOrdebyMethod, tempList.AsQueryable().Expression, lambda); // {tempList.OrderBy(p => p.ID)}
var results = tempList.AsQueryable().Provider.CreateQuery(orderByMethodExpression);
return orderByMethodExpression;
}
相关部分是对 Expression.Call
的调用,我必须在其中提供 IQueryable
才能正常工作,但我希望能够在不指定现有 IQueryable
.
这可能吗?
编辑:
既然我想到了这一点,我实际上根本不需要这样做......将 IQueryable 作为参数发送到 GetQuery 方法是非常有意义的。不过我会继续问这个问题。
您可以将其创建为从 IQueryable 到 IOrderedQueryable 的另一个表达式,例如:
public Expression getOrderByQuery<T>(PropertyInfo col)
{
var orderByMethod = typeof(Queryable).GetMethods().Single(
method => method.Name == "OrderBy"
&& method.IsGenericMethodDefinition
&& method.GetGenericArguments().Length == 2
&& method.GetParameters().Length == 2);
var genericOrdebyMethod =
orderByMethod.MakeGenericMethod(typeof(T), col.PropertyType);
var parameter = Expression.Parameter(typeof(T), "p"); // {p}
var property = Expression.Property(parameter, col); // {p.ID}
var lambda = Expression.Lambda<Func<T, int>>(property, parameter); // {p => p.ID}
var paramList = Expression.Parameter(typeof(IQueryable<T>));
// {tempList.OrderBy(p => p.ID)}
var orderByMethodExpression = Expression.Call(genericOrdebyMethod, paramList, lambda);
return Expression.Lambda(orderByMethodExpression, paramList);
}
我这样使用它,我的列表得到排序:
var tempList = new List<PlayerDTO>()
{
new PlayerDTO(2, "First"),
new PlayerDTO(1, "Second")
};
var e = (Expression<Func<IQueryable<PlayerDTO>, IOrderedQueryable<PlayerDTO>>>)
getOrderByQuery<PlayerDTO>(typeof(PlayerDTO).GetProperty("Id"));
e.Compile().Invoke(tempList.AsQueryable()).Dump();