将多类型OrderBy表达式存储为属性
在一个通用的抽象基类中,我存储了几个用于排序的表达式:
public Expression<Func> OrderByString { get; set; } public Expression<Func> 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> Order { get; set; }
无法将类型’System.Int32’强制转换为’System.Object’。 LINQ to Entities仅支持转换实体数据模型基元类型。
此外,如果我尝试轻微的黑客,这也不起作用:
public Expression<Func> Order { get; set; } this.Order = c => c.OrderID.ToString();
LINQ to Entities无法识别方法’System.String ToString()’方法,并且此方法无法转换为存储表达式。
听起来你想要一种方法在某个地方堆积一堆Ordering并应用它。 但是你不能因为每个Expression都有自己的类型,在调用OrderBy时由编译器检查。 调用OrderBy时必须具有这两种类型,但必须有一种类型才能放入同一列表中。
隐藏界面后面的第二种类型。
public interface IOrderer { IOrderedQueryable ApplyOrderBy(IQueryable source); IOrderedQueryable ApplyOrderByDescending(IQueryable source); IOrderedQueryable ApplyThenBy(IOrderedQueryable source); IOrderedQueryable ApplyThenByDescending(IOrderedQueryable source); } public class Orderer : IOrderer { private Expression> _orderExpr; public Orderer(Expression> orderExpr) { _orderExpr = orderExpr; } public IOrderedQueryable ApplyOrderBy(IQueryable source) { return source.OrderBy(_orderExpr); } public IOrderedQueryable ApplyOrderByDescending(IQueryable source) { return source.OrderByDescending(_orderExpr); } public IOrderedQueryable ApplyThenBy(IOrderedQueryable source) { return source.ThenBy(_orderExpr); } public IOrderedQueryable ApplyThenByDescending(IOrderedQueryable source) { return source.ThenByDescending(_orderExpr); } } public class OrderCoordinator { public List> Orders { get; set; } public OrderCoordinator() { Orders = new List>(); } //note, did not return IOrderedQueryable to support ability to return with empty Orders public IQueryable ApplyOrders(IQueryable source) { foreach (IOrderer 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 coord = new OrderCoordinator (); coord.Orders.Add(new Orderer(c => c.Name)); coord.Orders.Add(new Orderer(c => c.FavNumber)); IQueryable query = Enumerable.Empty ().AsQueryable(); query = coord.ApplyOrders(query); string result = query.Expression.ToString(); } }
在调试器中:
result = "OrderingDemo.Customer[].OrderBy(c => c.Name).OrderBy(c => c.FavNumber)"
所以在你的情况下,而不是这个属性:
public Expression> Order { get; set; }
使用此属性
public IOrderer Order { get; set; }
如果您使用NuGet.org上的DynamicLinq库,这很容易做到。 这允许你编写像;
db.People.Where("Id == 8"); db.People.OrderBy("Created ASC");
这样您就可以将where子句保存或传递为字符串。 没有大惊小怪,没有麻烦。
考虑使用方法而不是属性。
public abstract IEnumerable ApplyOrdering( IEnumerable q ); ... public override IEnumerable ApplyOrdering( IEnumerable q ) { return q.OrderBy( c => c.CustomerID ); }
Amy B的答案很棒,我自己的解决方案就是基于它。 所以我的观点更多的是我需要的改进,我可能会及时改进。
public interface IOrderer { IOrderedQueryable Apply(IQueryable source); } public class OrderBy : IOrderer { private Expression> _orderExpr; public OrderBy(Expression> orderExpr) { _orderExpr = orderExpr; } public IOrderedQueryable Apply(IQueryable source) { return source.OrderBy(_orderExpr); } } public class ThenBy : IOrderer { private Expression> _orderExpr; public ThenBy(Expression> orderExpr) { _orderExpr = orderExpr; } public IOrderedQueryable Apply(IQueryable source) { return ((IOrderedQueryable )source).ThenBy(_orderExpr); } } public class OrderCoordinator { public List> Orders { get; private set; } = new List>(); public IQueryable ApplyOrder(IQueryable source) { foreach (IOrderer orderer in Orders) { source = orderer.Apply(source); } return source; } public OrderCoordinator OrderBy(Expression> orderByExpression) { Orders.Add(new OrderBy(orderByExpression)); return this; } // Can add more sort calls over time public OrderCoordinator ThenBy(Expression> orderByExpression) { Orders.Add(new ThenBy(orderByExpression)); return this; } }
使用类型指定协调器:
public OrderCoordinator OrderCoordinator { get; private set; } = new OrderCoordinator ();
指定排序顺序:
OrderCoordinator.OrderBy(e => e.MyStringProperty).ThenBy(e => e.MyIntProperty);
应用订购:
ordered = OrderCoordinator.ApplyOrder(ordered);