Home>

Foreword

Believe everyone onentity frameworkIt must be familiar.I believe linq to sql is one of its biggest highlights,But we have been using it until now and have never understood how it is done internally.Today we will briefly introduce iqueryable and iqueryprovider.

iqueryable interface

Let's talk about this interface first,Because we often see the return type of the linq to sql statement in using ef isiqueryableWe can look at the structure of this interface:

public interface iqueryable:ienumerable
{
 type elementtype {get;}
 expression expression {get;}
 iqueryprovider provider {get;}
}

If readers are more careful, they will find that linq to sql does not lead to actual queries.Only when we actually start using it does we start querying data from the database.

iqueryprovider interface

If we debug ef, we will see the generated t-sql statement. t-sql is derived from the analysis of expression trees,The core is the iqueryprovider interface. Here is the structure of the interface:

public interface iqueryprovider
{
 iqueryable createquery (expression expression);
 iqueryable<telement>createquery<telement>(expression expression);
 object execute (expression expression);
 tresult execute<tresult>(expression expression);
}

WherecreatequeryIt is responsible for parsing the expression tree.Of course, the processed results must be returned.In order to analyze the following statement,Of course, this is just analysis,You can get the query you need based on the expression tree.Like sql or whatever,is called only when the data is actually usedexecutemethod, at this time you can start the actual query based on the statement we analyzed.

Case Analysis

queryprovider class

We can never understand the principle without saying that,So below we will simply give an example to show.First we first implement the iqueryprovider interface, which will use a query class, this class will be introduced later,First we create a newqueryproviderclass implements the iqueryprovider interface, first we look atcreatequery<s>Method:

hereexpressionIt is passed to us,And the expression tree we need to deal with,Finally, return an example that implements the iqueryableinterface,In order for linq to perform the following query on this basis,Here we just create an instance of query and pass expression to it,Because this is just a demo, we did not actually parse the expression tree.(A lot of work to do here). Then there is the createquery method:

We can see this sentence:

What it really means is to createquery<>and the generic parameter iselementtype, the parameter isthisandexpression.

Finally,executemethod, pass aexpressionparameter and get the final result,The author directly writes the value here:

query class

JustqueryproviderNot useful yet, we also need a class that can save the state of the expression tree,Of course, it also includes that the result of our parsing expression can also be saved in it,In this way, in the execute method of iqueryprovider, we can execute and return the result according to the result of our analysis.

Here we can see the query expression value when creating this instance,If the expression parameter is not passed, the value is:

But in the following procedure, the expression in query will be the expression value in queryprovider.

At this point we have actually completed a simple example,We can start testing our results,The author is using the following code to test:

Ok, let's see how to analyze this linq statement.

First we look at the return value of expression in the query at the beginning (as shown below):

After getting this expression,Start to execute linq, the first is where item == 123.

Analysis where item == 123

Then we f5, you can see thein queryprovidercreatequery<s>hit, andexpressionThe parameters are shown below:

We see that the string inside iswhere (item =>(item == 123))Through this sentence, we can understand that where in Linq is actually using the where method and passing it the corresponding lambda expression. After analyzing the where part, here isfirstordefaultsection.

Analyzing firstordefault

When executed tofirstordefaultWhen we can check the value of t, we will find that t is actually the return value of createqueryin queryprovider.

Then we start to execute the followingfirstordefaultmethod and found that I would get againexpression, and the value of expression at this time is the abovecreatequery<t>Parameters passed to usexpression.

Then in this expression tree and represented by the expression treefirstordefaultThe values ​​of the method calls are stitched together,And call the executemethod in queryprovider, we can see the value of the parameter expression passed to us at this time.

At this point, a simple process is over.The last is to return the value of 123 written by the author.

Through the above example, we basically understand the process of its work.Below we will analyze our step by stepwhere item == 123Of course we will use recursion,So please sort out your own ideas,See step by step how to analyze this statement from an expression tree.

Analyzing expression trees in action

First we have a method for analyzing expression trees.Let ’s put this method inqueryproviderMedium:

public void analysisexpression (expression exp)
 {
 switch (exp.nodetype)
 {
 case expressiontype.call:
 {
 methodcallexpression mce=exp as methodcallexpression;
 console.writeline ("the method is {0}", mce.method.name);
 for (int i=0;i<mce.arguments.count;i ++)
 {
 analysisexpression (mce.arguments [i]);
 }
 }
 break;
 case expressiontype.quote:
 {
 unaryexpression ue=exp as unaryexpression;
 analysisexpression (ue.operand);
 }
 break;
 case expressiontype.lambda:
 {
 lambdaexpression le=exp as lambdaexpression;
 analysisexpression (le.body);
 }
 break;
 case expressiontype.equal:
 {
 binaryexpression be=exp as binaryexpression;
 console.writeline ("the method is {0}", exp.nodetype.tostring ());
 analysisexpression (be.left);
 analysisexpression (be.right);
 }
 break;
 case expressiontype.constant:
 {
 constantexpression ce=exp as constantexpression;
 console.writeline ("the value type is {0}", ce.value.tostring ());
 }
 break;
 case expressiontype.parameter:
 {
 parameterexpression pe=exp as parameterexpression;
 console.writeline ("the parameter is {0}", pe.name);
 }
 break;
 default:
 {
 console.write ("unknow");
 }
 break;
 }
 }

And increatequery<s>call this method

ps:nodetype in expression is very important,Because what is passed to us is the parent expression type, and we need to convert to the corresponding subclass according to the nodetype.Then we can get more detailed information.

expressiontype.call

We entered this branch based on the nodetype of the first exp.Because where is essentially ss calling the where method, we convert exp to the correspondingmethodcallexpressiontype so we can see the name of the method being called.

Of course, calling a method requires parameters,So you need to cycle belowargumentsto analyze specific parameters,It also includes the object that called this method,Naturally, we first analyze the object that calls this method,Here we make the first recursive call,Jumped to expressiontype.constant.

expressiontype.constant

nodetype is this type,We can useconstantexpressiontype to get the corresponding parameters,Through value we can get the object that called the where method,Of course, we will not continue to analyze here.

So we continue to jump to the previous for loop and start analyzing the second parameter.This is the item =>item == 123 part.

expressiontype.quote

People who have been exposed to lambdas may think that the type should be lambda, but they will not actually jump directly to it.But first jump to quote, then we convert tounaryexpressiontype before moving on tooperandattribute, and the nodetype of this attribute is lambda. Personally, I think this should be a way to distinguish between lambda and ordinary,Because where can not only receive lambdas but also regular methods,So this layer is needed here.

expressiontype.lambda

Jump to this,Everyone will not feel strange,Here for brevity.The author did not analyze the parameters,But directly analyzebodypart, because this part is our key.

expressiontype.equal

We see this lambda is very simple, it is an equality comparison,So it jumps directly to equal, and of course there are corresponding enums such as and, or,At this step, we can directly analyze left and right. Of course, there is another episode here.It is when I jump to this enum that when I look at the type of exp,Is actuallylogicalbinaryexpressiontype, notbinaryexpressiontype, and then viewed with reflector,I just hehe.

I was weird at the time,Why is there no such type?I finally realized that it was this one.So far,Let's continue to analyze the left and right parameters of this equality operation.

The first analysis is the left parameter item.

expressiontype.parameter

item picked here,And convert it intoparameterexpressiontype, the author only outputs the name of the parameter here.

The parameter analysis to the left is complete,We begin to analyze the parameters on the right.

expressiontype.constant

We can easily think of the corresponding value as 123. At this point, the entire expression is analyzed.

Let's look at the output of the final console.

Here I also want to state a question,Is that we should understand the principles of the various libraries we use,This is convenient for us to add some functions that are in line with actual development in the future.Of course this is not a waste of time.But to increase the time for future project development,With continuous accumulation,We will find that many duplicate functions do not require us to write repeatedly.And the time saved we can do what we want to do,So we have to be a thoughtful lazy programmer.

c
  • Previous Continuous odd number (n + 2 * x) implemented by Java is a composite algorithm
  • Next The most concise C # barcode image ideas and examples in history