LINQ Expression Tree Serialization

6 posts, 0 answers
  1. Pål
    Pål avatar
    53 posts
    Member since:
    Sep 2012

    Posted 25 Jan 2010 Link to this post

    Hi.

    An excellent feature, which I really miss and think would be absolutely fabolus, is the abillity to serialize LINQ Expression trees.

    In n-tier applications this would play out as follows:

    1. A client creates a LINQ query for all clients

    var result = from c in scope.Extent<Client>() select c; 

    2. The expression is serialized
    XElement xmlExpression = new ExpressionSerializer().Serialize(result.Expression); 

    3. Using whatever means of transportation, the serialized xml expression is sent to the server.
    ObjectContainer container = Server.Extent<Client>.Execute(xmlExpression); 

    4. On the server side, the xml expression is replayed, filled in an object container and returned to the client.
    // Deserialize the xml expression tree  
    Expression expression = new ExpressionSerializer().Deserialize(xmlExpression);  
     
    // Execute expression  
    var result = objectScope.Extent<T>().Provider.Execute<T>(expression);  
     
    // Copy result into an object container  
    objectContainer.copyFrom(objectScope, "Items", result.ToList<T>, null);  
     
    // Return the object Container  
    return objectContainer; 

    I have played some around with this, but it fails on deserialization since it's impossible to create instances of "Telerik.OpenAccess.Query.ExtentQueryImpl<T>" unless you work at Telerik...

    Check out this link at MSDN blogs. They have already created ways to do this, and it contains source code and samples.
    Expression Tree Serialization

    Waiting in anticipation.

    Thanks

    Pål
  2. Jordan
    Admin
    Jordan avatar
    547 posts

    Posted 26 Jan 2010 Link to this post

    Hi Pål,

    It just occurred to me that although you cannot serialize the whole OpenAccess query, you can serialize the smaller expressions that are used to build it. These smaller expressions are the projection expression used in the Select extension method, the predicate expression used by the Where extension method, etc.

    In this way you should be able to serialize the expressions from which you will later be able to easily construct the query like in the code sample bellow:
    ExpressionSerializer serializer = new ExpressionSerializer();
    XElement predicateXml = serializer.Serialize(filter);
    // persist the serialized expression
     
    // some more code
     
    // load the serialized expression
    filter = serializer.Deserialize<Func<Customer, bool>>(predicateXml);
     
    IObjectScope objectScope = ObjectScopeProvider1.GetNewObjectScope();
    IQueryable<Customer> query = objectScope.Extent<Customer>().Where(filter);
    IList<Customer> customers = query.ToList();

    I hope this helps.

    All the best,
    Jordan
    the Telerik team

    Instantly find answers to your questions on the new Telerik Support Portal.
    Watch a video on how to optimize your support resource searches and check out more tips on the blogs.
  3. DevCraft banner
  4. Pål
    Pål avatar
    53 posts
    Member since:
    Sep 2012

    Posted 26 Jan 2010 Link to this post

    Hi!

    Thanks for the reply, but I'm not quite sure how to retrieve the "filter" you are talking about. I have tried using the .Expression property of the query and serialize this, but that failes.

    Could you give an example on how to retrieve the "filter".

    Thanks

    Pål
  5. Jordan
    Admin
    Jordan avatar
    547 posts

    Posted 27 Jan 2010 Link to this post

    Hi Pål,

    In the code from my previous post the filter parameter is defined earlier in the code as:
    Expression<Func<Customer, bool>> filter = c => c.City.StartsWith("S");

    Of course in your case the way of defining the predicate expressions may be different.
    Can you please share more details with us?

    All the best,
    Jordan
    the Telerik team

    Instantly find answers to your questions on the new Telerik Support Portal.
    Watch a video on how to optimize your support resource searches and check out more tips on the blogs.
  6. Pål
    Pål avatar
    53 posts
    Member since:
    Sep 2012

    Posted 27 Jan 2010 Link to this post

    Hi!

    Certainly, I'm trying to serialize a complete Expression tree obtained from objectScope.Extent<T>().

    The expression could be anything, depending on the LINQ query entered by the developer in the presentation layer.

    For this thread, i used as an example the LINQ query:
    var query = from c in objectScope.Extent<Client>()  
                select c; 

    which when "query.Expression" is serialized to XML, produces the following output:
    <MethodCallExpression NodeType="Call">  
      <Method MemberType="Method" MethodName="Select">  
        <DeclaringType> 
          <Type Name="System.Linq.Queryable" /> 
        </DeclaringType> 
        <Parameters> 
          <Type> 
            <Type Name="System.Linq.IQueryable`1">  
              <Type Name="Navita.Client" /> 
            </Type> 
          </Type> 
          <Type> 
            <Type Name="System.Linq.Expressions.Expression`1">  
              <Type Name="System.Func`2">  
                <Type Name="Navita.Client" /> 
                <Type Name="Navita.Client" /> 
              </Type> 
            </Type> 
          </Type> 
        </Parameters> 
        <GenericArgTypes> 
          <Type> 
            <Type Name="Navita.Client" /> 
          </Type> 
          <Type> 
            <Type Name="Navita.Client" /> 
          </Type> 
        </GenericArgTypes> 
      </Method> 
      <Object /> 
      <Arguments> 
        <ConstantExpression NodeType="Constant">  
          <Value>Extent&lt;Navita.Client&gt;</Value> 
          <Type> 
            <Type Name="Telerik.OpenAccess.Query.ExtentQueryImpl`1">  
              <Type Name="Navita.Client" /> 
            </Type> 
          </Type> 
        </ConstantExpression> 
        <UnaryExpression IsLifted="false" IsLiftedToNull="false" NodeType="Quote">  
          <Operand> 
            <LambdaExpression NodeType="Lambda">  
              <Body> 
                <ParameterExpression Name="c" NodeType="Parameter">  
                  <Type> 
                    <Type Name="Navita.Client" /> 
                  </Type> 
                </ParameterExpression> 
              </Body> 
              <Parameters> 
                <ParameterExpression Name="c" NodeType="Parameter">  
                  <Type> 
                    <Type Name="Navita.Client" /> 
                  </Type> 
                </ParameterExpression> 
              </Parameters> 
              <Type> 
                <Type Name="System.Func`2">  
                  <Type Name="Navita.Client" /> 
                  <Type Name="Navita.Client" /> 
                </Type> 
              </Type> 
            </LambdaExpression> 
          </Operand> 
          <Method /> 
          <Type> 
            <Type Name="System.Linq.Expressions.Expression`1">  
              <Type Name="System.Func`2">  
                <Type Name="Navita.Client" /> 
                <Type Name="Navita.Client" /> 
              </Type> 
            </Type> 
          </Type> 
        </UnaryExpression> 
      </Arguments> 
      <Type> 
        <Type Name="System.Linq.IQueryable`1">  
          <Type Name="Navita.Client" /> 
        </Type> 
      </Type> 
    </MethodCallExpression> 

    This is all fine and it can be transferred accross the wire to the business layer.

    However, on she server side, this needs to be deserialized into a query/expression which can be processed by OpenAccess, and if you take a look at this part of the XML:
        <ConstantExpression NodeType="Constant">  
          <Value>Extent&lt;Navita.Client&gt;</Value> 
          <Type> 
            <Type Name="Telerik.OpenAccess.Query.ExtentQueryImpl`1">  
              <Type Name="Navita.Client" /> 
            </Type> 
          </Type> 
        </ConstantExpression> 
    It requires the creation of a "Telerik.OpenAccess.Query.ExtentQueryImpl<T>".
    I did however, find a way to hook into the deserialization process and instantiate the type using "Telerik.OpenAccess.ExtensionMethods.Extent<T>(IObjectScope scope)" method.

    I Have only tried some simple LINQ queries, but will try and test some more.

    You wouldn't happen to have a set of LINQ 101 test for c# so I can run some tests?

    Anyway, I'll be happy to post any findings and how to extend the soultion (see link above) to work with OA.

    Regards

    Pål
  7. Jordan
    Admin
    Jordan avatar
    547 posts

    Posted 28 Jan 2010 Link to this post

    Hello Pål,

    What we have is a sample application that demonstrates the LINQ 101 queries with OpenAccess.
    You can find it here:
    http://www.telerik.com/community/code-library/orm/general/telerik-openaccess-orm-1-1-linq-samples.aspx

    I guess that if you modify it a little you could use it for your tests.
    It will be great if you can share your findings with the community.

    Regards,
    Jordan
    the Telerik team

    Instantly find answers to your questions on the new Telerik Support Portal.
    Watch a video on how to optimize your support resource searches and check out more tips on the blogs.
Back to Top
DevCraft banner