在一个通用的抽象基类中,我存储了几个用于排序的表达式:
public Expression<Func<T, string>> OrderByString { get; set; }
public Expression<Func<T, int>> OrderByInt { get; set; }
稍后将在通用基类中使用:
if (OrderByString != null)
{
results = results.OrderBy(OrderByString);
}
else if (OrderByInt != null)
{
results = results.OrderBy(OrderByInt);
}
最后,其中一个将在派生具体类的构造函数中设置:
this.OrderByString = c => c.CustomerID;
我不喜欢这样的事实,即我需要根据我想要OrderBy的属性类型使用单独的表达式。 ToString不适用于属性,因为LINQ to Entities不支持它。我所追求的是一种存储表达式的方法,该表达式选择任何要订购的属性而不管其类型。
如果我尝试一些更通用的东西,例如:
public Expression<Func<T, object>> Order { get; set; }
无法将类型'System.Int32'强制转换为'System.Object'。 LINQ to Entities仅支持转换实体数据模型基元类型。
此外,如果我尝试轻微破解,这也不起作用:
public Expression<Func<T, string>> Order { get; set; }
this.Order = c => c.OrderID.ToString();
LINQ to Entities无法识别方法'System.String ToString()'方法,并且此方法无法转换为商店 表达
答案 0 :(得分:12)
听起来你想要一种方法在一个列表中堆积一堆Ordering并应用它。但你不能因为每个Expression都有自己的类型,编译器在调用OrderBy时会检查它。调用OrderBy时必须有这两种类型,但是必须有一种类型放在同一个列表中。
隐藏界面后面的第二种类型。
public interface IOrderer<T>
{
IOrderedQueryable<T> ApplyOrderBy(IQueryable<T> source);
IOrderedQueryable<T> ApplyOrderByDescending(IQueryable<T> source);
IOrderedQueryable<T> ApplyThenBy(IOrderedQueryable<T> source);
IOrderedQueryable<T> ApplyThenByDescending(IOrderedQueryable<T> source);
}
public class Orderer<T, U> : IOrderer<T>
{
private Expression<Func<T, U>> _orderExpr;
public Orderer(Expression<Func<T, U>> orderExpr) { _orderExpr = orderExpr; }
public IOrderedQueryable<T> ApplyOrderBy(IQueryable<T> source)
{ return source.OrderBy(_orderExpr); }
public IOrderedQueryable<T> ApplyOrderByDescending(IQueryable<T> source)
{ return source.OrderByDescending(_orderExpr); }
public IOrderedQueryable<T> ApplyThenBy(IOrderedQueryable<T> source)
{ return source.ThenBy(_orderExpr); }
public IOrderedQueryable<T> ApplyThenByDescending(IOrderedQueryable<T> source)
{ return source.ThenByDescending(_orderExpr); }
}
public class OrderCoordinator<T>
{
public List<IOrderer<T>> Orders { get; set; }
public OrderCoordinator() { Orders = new List<IOrderer<T>>(); }
//note, did not return IOrderedQueryable to support ability to return with empty Orders
public IQueryable<T> ApplyOrders(IQueryable<T> source)
{
foreach (IOrderer<T> orderer in Orders)
{
source = orderer.ApplyOrderBy(source);
}
return source;
}
}
public class Customer
{
public string Name { get; set; }
public int FavNumber { get; set; }
}
public class Tester
{
public void Test()
{
OrderCoordinator<Customer> coord = new OrderCoordinator<Customer>();
coord.Orders.Add(new Orderer<Customer, string>(c => c.Name));
coord.Orders.Add(new Orderer<Customer, int>(c => c.FavNumber));
IQueryable<Customer> query = Enumerable.Empty<Customer>().AsQueryable();
query = coord.ApplyOrders(query);
string result = query.Expression.ToString();
}
}
在调试器中:
result = "OrderingDemo.Customer[].OrderBy(c => c.Name).OrderBy(c => c.FavNumber)"
所以在你的情况下,而不是这个属性:
public Expression<Func<T, U>> Order { get; set; }
使用此属性
public IOrderer<T> Order { get; set; }
答案 1 :(得分:1)
如果您使用NuGet.org上的DynamicLinq库,这很容易做到。这允许您编写像;
这样的查询db.People.Where("Id == 8");
db.People.OrderBy("Created ASC");
这样您就可以将where子句保存或传入字符串。没有大惊小怪,没有麻烦。
答案 2 :(得分:1)
Amy B's答案很棒,我自己的解决方案就是基础。 所以我的观点更多的是我所需要的改进,我可能会及时改进。
public interface IOrderer<TItem>
{
IOrderedQueryable<TItem> Apply(IQueryable<TItem> source);
}
public class OrderBy<TItem, TType> : IOrderer<TItem>
{
private Expression<Func<TItem, TType>> _orderExpr;
public OrderBy(Expression<Func<TItem, TType>> orderExpr)
{
_orderExpr = orderExpr;
}
public IOrderedQueryable<TItem> Apply(IQueryable<TItem> source)
{
return source.OrderBy(_orderExpr);
}
}
public class ThenBy<TItem, TType> : IOrderer<TItem>
{
private Expression<Func<TItem, TType>> _orderExpr;
public ThenBy(Expression<Func<TItem, TType>> orderExpr)
{
_orderExpr = orderExpr;
}
public IOrderedQueryable<TItem> Apply(IQueryable<TItem> source)
{
return ((IOrderedQueryable<TItem>)source).ThenBy(_orderExpr);
}
}
public class OrderCoordinator<TItem>
{
public List<IOrderer<TItem>> Orders { get; private set; } = new List<IOrderer<TItem>>();
public IQueryable<TItem> ApplyOrder(IQueryable<TItem> source)
{
foreach (IOrderer<TItem> orderer in Orders)
{
source = orderer.Apply(source);
}
return source;
}
public OrderCoordinator<TItem> OrderBy<TValueType>(Expression<Func<TItem, TValueType>> orderByExpression)
{
Orders.Add(new OrderBy<TItem, TValueType>(orderByExpression));
return this;
}
// Can add more sort calls over time
public OrderCoordinator<TItem> ThenBy<TValueType>(Expression<Func<TItem, TValueType>> orderByExpression)
{
Orders.Add(new ThenBy<TItem, TValueType>(orderByExpression));
return this;
}
}
指定协调员,类型为:
public OrderCoordinator<MyObjectType> OrderCoordinator { get; private set; } = new OrderCoordinator<MyObjectType>();
指定排序顺序:
OrderCoordinator.OrderBy(e => e.MyStringProperty).ThenBy(e => e.MyIntProperty);
应用订购:
ordered = OrderCoordinator.ApplyOrder(ordered);
答案 3 :(得分:0)
考虑使用方法而不是属性。
public abstract IEnumerable<T> ApplyOrdering( IEnumerable<T> q );
...
public override IEnumerable<T> ApplyOrdering( IEnumerable<T> q )
{
return q.OrderBy( c => c.CustomerID );
}