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
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.
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.
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.