LINQ series (4) -- Expression Tree provider

Source: Internet
Author: User

sorry, I have not written a blog for such a long time, this series is not continued. I want to explain that this is the case because I have been busy with changing jobs. After changing jobs, the new company cannot access the Internet during work hours. After this period of time, I think I will try to adjust the time and status in the future. I should post at least one blog article in a week. By the way, after this series is over, I may write a message about prism series. I hope you can come and join us, I used to HP eds-Wuhan engaged . net developed, now in the light court navigation data (Wuhan) limited company engaged in . net development.

OK,This is the case. Let's proceed to the topic.

First, let's clarify a question. The literal translation of LINQ is language integration query. As the name suggests, it is used for query. As mentioned earlier, there is a local data source with the ability to use the LINQ to object function, remote applications include: LINQ to SQL, LINQ to dataset, LINQ to entities, and LINQ to XML. What does the expression tree do? Is the expression tree used to describe or save query conditions?

Answer: No. To be accurate, a method (function) can do anything in the Expression Tree. Before explaining what the expression tree can do and how to do it, let's outline the structure. PreviousArticleWe have already mentioned the inheritance structures of ienumerable <t> and iqueryble <t>, so today we will start from the provider in my previous blog post, as to the overall detailed structure, I will talk about it in the last article in this series.

This is a picture I extracted from my blog post on terrylee.

From this figure, we can see that iqueryable <t> inherits from iqueryable, and iqueryable has three members. Next we will talk about the usage of these three members.

We can refer to the information on msdn: http://msdn.microsoft.com/zh-cn/library/system.linq.iqueryable_members.aspx

Elementtype:ObtainIqueryableThe type of the elements returned when this instance is associated with the expression tree.

Expression:Obtain andIqueryableThe Expression Tree associated with the instance.

Provider:Obtain the query information associated with the data source.Program.

According to the previous article in terrylee: all the methods or lambda expressions defined in the query expression will be represented by the expression attribute, in the end, the provider translates the language into the query language of the corresponding data source. The data source may be a database, XML file, or WebService. This interface is very important. This interface must be implemented in custom LINQ provider. Similarly, standard query operations for iqueryable are implemented by the extension method in queryable.

I believe everyone should remember that we mentioned earlier that ienumerable <t> and iqueryable <t> use two sets of things. The extension method of ienumerable <t> is defined in the enumerable class, the iqueryable <t> method is defined in the queryable class.

Next, let's take a look at how an extension method in the queryable class works, and take a look at the roles of iqueryable members.

Public static Iqueryable <Tsource> where <tsource> ( This Iqueryable <Tsource> source,
Expression < Func <Tsource, Bool > Predicate)
{
If (Source = Null )
{
Throw Error. argumentnull ( "Source" );
}
If (Predicate = Null )
{
Throw Error. argumentnull ( "Predicate" );
}
Return Source. provider. createquery <tsource> (
Expression . Call ( Null , (Methodinfo) methodbase. getcurrentmethod ())
. Makegenericmethod ( New Type [] { Typeof (Tsource )}),
New Expression [] {Source. expression, Expression . Quote (predicate )}));
}

In this example, we can see source. expression is used to represent the query expression, while source. the provider translates the language into the query language of the corresponding data source. To make it more intuitive, let's look at the Extension Method in enumerable:

Public static Ienumerable <Tsource> where <tsource> (
This Ienumerable <Tsource> source,
Func <Tsource, Bool > Predicate)
{
If (Source = Null )
{
Throw Error. argumentnull ( "Source" );
}
If (Predicate = Null )
{
Throw Error. argumentnull ( "Predicate" );
}
Return Whereiterator <tsource> (source, predicate );
}

We can see that in this process, the query expression is not received and the expression is translated into the query language of the corresponding data source, it directly introduces a predicate expression (equivalent to the logic of an anonymous method) whereiterator <tsource> (source, predicate );

Let's take a look at the iqueryprovider interface. Let's take a look at the figure.

We can see that there are actually only two methods in this interface. Createquery and execute (generic and non-generic ). Let me explain the two methods.

According to msdn information: http://msdn.microsoft.com/zh-cn/library/bb549043.aspx

If you specify an expression tree,CreatequeryMethod to create a newIqueryable<(<(T>)>)Object. The query represented by the returned object is associated with a specific LINQ provider.

Most ofQueryableThe standard query operator method calls this method. These standard query operator methods will passMethodcallexpression.

I understand that this method is to associate the query data source with the expression, that is, to specify the expression of a query data source iqueryable <t>.

When we actually execute the query operation on the foreach data source, we call the execute method. Execute returns a single value. The execute method specifically accesses the exepressiontree, and converts the expression tree to the logic that can be recognized by the corresponding data source. We can take a look at the two methods through a document on msdn: http://msdn.microsoft.com/zh-cn/library/bb546158.aspx

Public Class Terraserverqueryprovider: iqueryprovider
{
Public Iqueryable createquery (expression)
{
Type elementtype = typesystem. getelementtype (expression. type );
Try
{
Return (Iqueryable) activator. createinstance (typeof (queryableterraserverdata <>). makegenerictype (elementtype ), New Object [] { This , Expression });
}
Catch (System. reflection. targetinvocationexception tie)
{
Throw tie. innerexception;
}
}

// queryable's collection-returning standard query operators call this method.
Public iqueryable createquery (expression)
{< br> return New queryableterraserverdata ( This , expression);
}

Public Object execute (expression)
{< br> return terraserverquerycontext. execute (expression, false );
}

// Queryable's "single value" standard query operators call this method.
// It is also called from queryableterraserverdata. getenumerator ().
PublicTresult execute <tresult> (expression)
{
BoolIsenumerable = (typeof (tresult). Name ="Ienumerable '1");

Return(Tresult) terraserverquerycontext. Execute (expression, isenumerable );
}
}

To find out execute, let's take a look at what terraserverquerycontext has.

Class Terraserverquerycontext
{
// Executes the expression tree that is passed to it.
Internal Static Object execute (expression, Bool Isenumerable)
{
// The expression must represent a query over the data source.
If (! Isqueryoverdatasource (expression ))
Throw New Invalidprogramexception ( "No query over the data source was specified ." );

// find the call to where () and get the lambda expression predicate.
innermostwherefinder wherefinder = New innermostwherefinder ();
methodcallexpression whereexpression = wherefinder. getinnermostwhere (expression);
lambdaexpression = (lambdaexpression) (unaryexpression) (whereexpression. arguments [1]). operand;

// send the lambda expression through the partial evaluator.
lambdaexpression = (lambdaexpression) evaluator. partialeval (lambdaexpression);

// get the place name (s) to query the Web service.
locationfinder LF = New locationfinder (lambdaexpression. body);
List string locations = lf. locations;
If (locations. count = 0)
throw New invalidqueryexception ( " you must specify at least one place name in your query. ");

// Call the web service and get the results.
Place [] Places = webservicehelper. getplacesfromterraserver (locations );

// Copy the ienumerable places to an iqueryable.
Iqueryable <place> queryableplaces = places. asqueryable <place> ();

// copy the expression tree that was passed in, changing only the first
// argument of the innermost methodcallexpression.
expressiontreemodifier treecopier = New expressiontreemodifier (queryableplaces);
Expression newexpressiontree = treecopier. copyandmodify (expression);

// This step creates an iqueryable that executes by replacing queryable methods with enumerable methods.
If (isenumerable)
return queryableplaces. provider. createquery (newexpressiontree);
else
return queryableplaces. provider. execute (newexpressiontree);
}

private static bool isqueryoverdatasource (expression)
{< br> // If expression represents an unqueried iqueryable data source instance,
/expression is of Type constantexpression, not methodcallexpression.
return (expression is methodcallexpression );
}< BR >}< br> This is a special case. It is the process of executing the access Expression Tree in the execute method and turning the logic in the expression tree into WebService.
The following is also the msdn information on

ExecuteMethod will execute the query that returns a single value (rather than the enumerated sequence of values. If the enumeration contains the Expression Tree that returns the enumerated resultsIqueryable<(<(T>)>)These expression trees are executed.

Returns a single resultQueryableThe standard query operator method is called.Execute. These standard query operator methods will passMethodcallexpression.

Finally, I will post a time sequence diagram of LINQ to SQL. Source: http://www.rainsts.net/article.asp? Id = 537

Okay, there are so many content about the provider. You are welcome to leave a message for me. In the next article, I will write some simple content to write the construction and application of the Specific Expression Tree.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.