将多类型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子句保存或传递为字符串。 没有大惊小怪,没有麻烦。

http://nuget.org/List/Packages/DynamicLINQ

考虑使用方法而不是属性。

 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);