none
Reuse a Linq Expression as part of the select clause

    Question

  • I've just started converting parts of an application over to Linq to SQL and I noticed that certain parts of the code are getting redundant and thus error prone so I've been looking into some clever ways to consolidate the behavior and promote reuse.

    var query1 =
        from c in myContext.Customer
        where c.FirstName.StartsWith("S")
        select new
        {
            c.FirstName,
            c.LastName,
            Phone = c.PhonePreference = "work" ? c.WorkPhone : c.HomePhone
        };
    
    var query2 =
        from c in myContext.Customer
        join o in myContext.Order on c.CustomerID equals o.CustomerID
        where c.FirstName.StartsWith("B")
        select new
        {
            o.Quantity,
            ContactPhone = c.PhonePreference = "work" ? c.WorkPhone : c.HomePhone
        };


    Now, at the moment what I'm interested in is the calculated fields "Phone" from query1 and "ContactPhone" from query2 which obviously repeat the same inline expression. What I'm wondering is whether there is any way to write this expression once and then reuse it in several places by calling similiar to how one would call a function.

    I know I can create a function that provides this behavior but that would cause the query to execute on the client side as opposed to SQL which is not what I want. I instead want to keep the end expression tree the same as if I wrote the expression inline but to define the actual expression in one place.

    What I've done so far is try to write an expression that looks like the following but I have no idea how to invoke in within the initialize of my anonymous type as shown in the previous example.

    public static Expression<Func<string, string, string, string>> GetPhone = 
        (preference, homePhone, workPhone) => preference == "work" ? workPhone : homePhone;


    • Edited by kainhart Monday, July 27, 2009 3:44 PM
    Monday, July 27, 2009 3:33 PM

All replies

  • See http://damieng.com/blog/2009/06/24/client-side-properties-and-any-remote-linq-provider
    Kristofer - Huagati Systems Co., Ltd. - Cool tools for Linq-to-SQL and Entity Framework: www.huagati.com/dbmltools (VS designer add-in), www.huagati.com/L2SProfiler (query profiler for L2S)
    Monday, July 27, 2009 3:46 PM
    Answerer
  • I'm sorry but I just don't see how the link you cited answers my question. Maybe it's buried in there somewhere and if so could you provide an example here in the forum please.
    Monday, July 27, 2009 3:53 PM
  • Even though LINQ to SQL would support it, there is no way to write an invocation over an expression tree based lambda, so you can't reuse it that way.

    What you could do is put the projection of the things you want to compute into a base query


    var custsWithContactPhone = from c in db.Customers
                                               select new { c, ContactPhone = c.PhonePreference == "work" ? c.WorkPhone : c.HomePhone };


    Then you can do this:


    var query2 = from x in custsWithContactPhone
                        join o in db.Orders on x.c.CustomerID equals o.CustomerID
                        where x.c.FirstName.StartsWith("B")
                        ...;

    Of course this requires you to for the base query each time you have a new DataContext. 

    What you then could do is use a compiled query.

    var fnQuery = CompiledQuery.Compile((MyDataContext dc) => from c in dc.Customers select new {c, ContactPhone = ...});

    And then use the function as the root of your next query:

    var query2 = from x in fnQuery(db)
                        join o in db.Orders on x.c.CustomerID equals o.CustomerID
                        ...

    LINQ to SQL is smart enough to see through this 'compiled query' and access its inner expression tree w/o causing two queries to execute.


    Wayward LINQ Lacky
    Monday, July 27, 2009 7:33 PM
    Moderator
  • So I guess your answer is that there is really no way to reuse expressions themselves from the stand point of the projection. I'm aware that I can reuse them for use within the Where() method that takes an expression as well as redefining the whole projection via the Select() method however as originally mentioned I'm interested in reusing expressions as portions of the projection instead. My thinking is that if I can write it inline, there should be some way to product the same effect within the expression tree in some way that can reference an existing expression. Perhapse there is a way to achieve this by hacking the expression tree directly? If so maybe I can abstract that hack into an extension method or something to abstract the complexity.

    The main problem that I have with method you have suggested is that it involves queries that return anonymous types. Even though it is easy to reuse these within a single method it becomes difficult if not near impossible to reuse them between separate methods. I'm looking to define expressions as a sort of expression library for well known operations for our data access layer. The idea is to produce reusable pieces of logic similar to T-SQLs scalar value User Defined Functions which can be reused in various places and parametrized.
    Monday, July 27, 2009 9:29 PM
  • Hi,

    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). It works along the lines of you suggested approach (rewriting expression trees).

    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.

    Thursday, June 14, 2012 6:08 PM