refactoring LINQ IQueryable expression to remove duplicated portions of queries

前端 未结 3 747
滥情空心
滥情空心 2021-02-09 11:40

I have some linq queries that have redundancy I\'d like to factor out a single piece of code. These are join experssions that are IQueryable, and its important I don\'t cause t

相关标签:
3条回答
  • 2021-02-09 12:20

    We had the same problem. It is not supported out of the box and it is a major problem for LOB applications. I ended up writing a code-project article about LINQ expressions reuse, including a very small utility called LinqExpressionPrjection that enables the reuse in projections (including into anonymous types).

    Find the article here.

    You can get the assembly for the projection reuse as a nuget package and the source is on CodePlex.

    Some time has passed since your post. I hope it is still helpful for you. If not, maybe for others reading this thread.

    0 讨论(0)
  • 2021-02-09 12:20

    Another important way to factor linq expressions is to pass expressions around, for example:

    X GetSomeX(Expression<Func<Y, X>> map)
    {
        return SourceOfYs.Select(map);
    }
    

    I got the idea by looking into the article of Barak's article - and even though he does a bit more on that topic, I thought I mention this piece again here. It seems to be an obvious first thing to point out directly.

    0 讨论(0)
  • 2021-02-09 12:32

    Sorry to answer my own question, but I found a good solution. I think though that depending on what you're trying to do, there are different way to factor out different LINQ expressions without evaluating the IQueryable. So I hope people share alternative solutions.

    My solution was to create a "view" for the factored out query. I call it a view because it has a lot in common with a SQL view (from the perspective of a LINQ client). Unlike a SQL view though, it cannot be indexed or have columns persisted. So using this view becomes a bottleneck, it would be appropriate to use an actual SQL view.

    static public class MyDataContextExtension
    {
        // The view exposes OrderSummary objects
        public class OrderSummary
        {
            public OrderID { get; set; }
            public string FirstProductListed { get; set; }
        }
    
        static public IQueryable<OrderSummary> OrderySummaryView(this MyDataContext db)
        {
             return (
                  from O in db.Orders
                  join OD in db.OrderDetails on O.OrderID equals OD.OrderID into OrderDetails
                  let AProductBought = OrderDetails.First().Select(OD => OD.Product.ProductName)
                  let TotalCost = OrderDetails.Aggregate(0
                  select new OrderSummary()
                  {
                      OrderID = OD.OrderID,
                      FirstProductListed = AProductBought.FirstOrDefault()
                  };
        }
    }
    

    With this, I can factor out the duplicated portion of the query, replacing the original query with the following:

    var result = 
    from T in db.Transactions
    join OS in db.OrderSummaryView() on T.OrderID equals OS.OrderID
    select new
    {
      TransactionID = T.TransactionID,
      OrderID = T.OrderID,
      FirstProductBought = OS.FirstProductListed
    };
    

    You can imagine other columns being added... I think one cool thing is that if you add extra columns but don't use them in your final select, LINQ won't actually query for those things from the database.

    0 讨论(0)
提交回复
热议问题