1. Loop execution object model, fragmented execution model (pseudo recursive invocation)

This topic may be a bit distant, but it is related to the design structure of the whole LINQ framework. At least before I understood the original meaning of LINQ, I kept having such models in my mind, which helped me understand the design principles of LINQ. In fact, I first got to know the loop model and fragmentation model in the first two months. At that time, I was lucky to get to know the knowledge of enterprise application architecture, which has many design skills of business fragmentation. In fact, understanding these so-called design models will greatly broaden our horizon, after all, the research framework is to study its design principle, its existence is bound to solve a certain kind of problems, problems drive its design model. So when we study such models, we are actually unconsciously understanding the nature of the problem.

What exactly is the loop execution model? How does it relate to fragmentation? What’s the secret of pseudo-recursive invocation? We have to solve all of these problems before we can move on to the next thing. Actually loop execution, fragmentation, false are different perspectives on the problem of recursion call, just as we often use dependency inversion and inversion of control and dependency injection these words to describe the design principle, design method, they are all in order to solve some problem exist, through clever design to achieve perfect effect. This is actually the case here, so let’s break it down.

There is no one who does not understand the principle of recursion, the use of recursion is also very common, through the recursive algorithm we can solve the big problem that cannot be solved, by breaking the big problem into multiple small problems of the same data structure and then let the computer repeat the calculation on the line. The most common is traversing the tree structure of the object, such as: XML, each node is the same object, so the recursive call method is also the same method, but repeated calls will generate multiple call stack, in order to call the end of the stack in the reverse order to get a complete data structure.

In LINQ, there is no way to generate the desired expression tree by calling a method multiple times. A Where query expression extension method may be used not only by LINQ query expressions, but also by ORM entry methods. For example, when an Update is performed, Where conditions are required for the Update. The same is true for Delete. (Of course, the design principle behind LINQ is not specific to LINQ technology, but is a general design pattern for a class of problems.) So how do we constructed a similar recursive structure, but not a recursive algorithm method 1 is likely to be 2 calls, method 2 is likely to be called by method 1, so a lot of methods, N method to express different semantics, the structure of the specific consumer demand, so there appears the concept of fragmentation, only after the fragmentation can maximum restructuring, Now that we can reassemble it we have an execution model of the loop. The perfect, seemingly simple, yet insightful model is only the tip of the iceberg. There have been many successful cases in enterprise architecture and domain-driven design. Otherwise, it would not be called design pattern. It seems a little difficult to explain computer program problems in the way of text, but the way of code + graphic analysis is the most suitable for our programmer’s habit of thinking. Let me use a simple example and some simple diagrams to share the relationship between these pattern languages.

We certainly know that there will be a lot of gifts placed in the supermarket to buy during the Spring Festival, but we all know a hidden rule, is that the packaging of these goods spend a lot of effort, a layer of a layer, in fact, the things inside may be very humble, this is also a marketing means. We don’t care what is inside, we now need to design a model that can arbitrarily carry out N layers of packaging, a product of left and right layers of packaging, packaging how many times we don’t care, we can provide a method to carry out N layers of packaging.

/// <summary> 
   ///Commodity abstract class
   /// </summary> 
   public abstract class Merchandise 
   { 
       /// <summary> 
       ///Trade name
       /// </summary> 
       public string MerchandiseName { get; protected set; } 
       /// <summary> 
       ///The unit price
       /// </summary> 
       public int UnitPrice { get; protected set; } 
       /// <summary> 
       ///The number of
       /// </summary> 
       public int Number { get; protected set; }}/// <summary> 
   ///apple
   /// </summary> 
   public class Apple : Merchandise 
   { 
       public Apple(){}private void Init() 
       { 
           base.MerchandiseName = "Imported Thai apples"; 
           base.UnitPrice = 8;//8 yuan each
           base.Number = 3;//3 to a basket}}/// <summary> 
   ///banana
   /// </summary> 
   public class Banana : Merchandise 
   { 
       public Banana(){}private void Init() 
       { 
           base.MerchandiseName = "Yunnan Green Banana"; 
           base.UnitPrice = 3;//3 yuan each
           base.Number = 10;//10 pieces to a basket}}/// <summary> 
   ///Commodity Packaging
   /// </summary> 
   public static class MerchandisePack 
   { 
       /// <summary> 
       ///Stick a logo
       /// </summary> 
       public static Merchandise PackLogo(this Merchandise mer) 
       { 
           return mer; 
       } 
       /// <summary> 
       ///Pack a red box
       /// </summary> 
       public static Merchandise PackRedBox(this Merchandise mer) 
       { 
           return mer; 
       } 
       /// <summary> 
       ///Pack a blue box
       /// </summary> 
       public static Merchandise PackBlueBox(this Merchandise mer) 
       { 
           return mer; 
       }
Copy the code

So simple code I will not explain, here is just for demonstration and did not add useless code, so as not to waste your time.

Let’s look at the key part of the code:

Apple apple = new Apple(); 
           apple.PackLogo().PackBlueBox().PackRedBox().PackLogo(); 

           Banana banana = new Banana(); 
           banana.PackRedBox().PackBlueBox().PackLogo();
Copy the code

I think this code can completely convince us how flexible the extensibility of fragmentation is. At the beginning, Apple needed to stick a small logo on it, as we apple eaters know. Since it is a special holiday now, in order to give a little Surprise to the recipients of gifts, we are required to have several layers of packaging for the products. This model is really convenient.

Fully implements the ability to extend independently without dragging wrapped methods into domain objects, clean and tidy.



Through this architecture model for system development, we know at a glance every logical process of the system, more like a workflow of execution, first what is then what. It’s not like IF ELSE is a mess of logic that’s hard to maintain. It is a kind of enterprise application architecture pattern. Of course, the repeated use of one or two methods in LINQ is only possible with LINQ to Object, but almost never with LINQ to Entity. In general, only the keyword exists in different query contexts. Here is to explain the design principle behind it.

2. N-layer object execution model (vertical and horizontal contrastive chain extension method)

In fact, I did not intend to add this section, but considering that there must be some friends who do not understand how multiple objects coordinate to solve certain kinds of problems. The IQueryable interface appears to be an object, but is a member of a full IQueryable network. Where are n-level objects represented? Layer 1 object processing begins at the outset of the IQueryable extended methods, and repeated loop pseudo-recursive invocations form an N-layer object model. LINQ query expression and query method are actually one-to-one correspondence, extension method is vertical concept, and LINQ query expression is horizontal, in fact, the two belong to the corresponding relationship. For details, please refer to my article “NET In-depth Analysis of LINQ Framework (Article 4)”.

3.LINQ query expressions and chained query methods are empty shells

LINQ’s real intention is to facilitate our construction of expression trees (ExpressionTree), manual construction of expression trees friends will feel very troublesome (interested in dynamic expressions can refer to my “.net in-depth analysis of LINQ framework (third article) “article), So we can call extension methods by writing Lambda directly, and since LambdaExpression comes from Expression, and Expression comes from LambdaExpression, don’t get confused, Expression actually simplifies the way we use expressions. For Expression compilation, the editor generates it for us, and at run time we just get ExpressionTree. LINQ query expressions are supported horizontally by extension methods. You can use extension methods without LINQ, but that can be cumbersome and slow to develop. The biggest problem is not that there is no uniform way to query all data sources. LINQ was intended and intended to provide a uniform way for us to query all data sources, which is important.

4 Detailed object structure diagram (Object execution principle)

The key point of this article is in this section, the above said so many words if friends can understand or not understand it is really a headache. In this section, I will provide a core LINQ implementation diagram. We will clearly see the object structure of the final LINQ expression tree, how it constructs a complete tree structure, how the IQueryProvider interface interacts with the IQueryProvider interface. Why IQueryable has lazy loading capability. At the end of this article, I will give you a small example of a complete Linq to Provider, which will definitely be enjoyed by those who like to extend Linq.



The chart above may seem confusing, but it is understandable that the DbQueryable lifecycle is over and over, and that the issue can be addressed in response to comments.

5. Can the one-to-one relationship between the IQueryable and IQueryProvider be changed to a one-to-many relationship

All iQueryyable objects have a matching IQueryProvider object. Frequent creation of IQueryProvider objects over the IQueryable node is wasteful. The internal structure that implements the IQueryable class can be modified to re-use the IQueryProvider object each time it is created. The IQueryProvider object does not have any intermediate state data. There are only CreateQuery and Execute methods. Here is only my small improvement ideas, do not need to consider these.

6. Complete custom query

The LINQ analysis is coming to an end, and this article will be the last in-depth LINQ analysis. Now that we’ve finished our analysis of LINQ, let’s write a small example that will serve as a prototype for extending LINQ. This example does not cover expression tree analysis, because expression tree analysis is not easy. There will be a special article to analyze the full structure of the expression tree, here is a comprehensive IQueryable and IQueryProvider implementation.

ORM has been one of our favorite frameworks to write about, and the customized IQueryable object entities are queried here. First, we need to extend the IQueryable interface to enable LINQ to query our own data context.

public class DbQuery<T> : IQueryable<T>, IDisposable 
    { 
        public DbQuery() 
        { 
            Provider = new DbQueryProvider(); 
            Expression = Expression.Constant(this);// The last expression will be a reference to the first IQueryable object.
        } 
        public DbQuery(Expression expression) 
        { 
            Provider = new DbQueryProvider(); 
            Expression = expression; 
        } 

        public Type ElementType 
        { 
            get { return typeof(T); } 
            private set { ElementType = value; }}public System.Linq.Expressions.Expression Expression 
        { 
            get; 
            private set; 
        } 

        public IQueryProvider Provider 
        { 
            get; 
            private set; 
        } 

        public IEnumerator<T> GetEnumerator() 
        { 
            return (Provider.Execute<T>(Expression) as IEnumerable<T>).GetEnumerator(); 
        } 

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() 
        { 
            return (Provider.Execute(Expression) as IEnumerable).GetEnumerator(); 
        } 

        public void Dispose(){}}Copy the code

The following need to implement the provider:

 public class DbQueryProvider : IQueryProvider
    {
        public IQueryable<TElement> CreateQuery<TElement> (System.Linq.Expressions.Expression expression)
        {
            return new DbQuery<TElement>();
        }

        public IQueryable CreateQuery(System.Linq.Expressions.Expression expression)
        {
            // There is no need to talk about expression tree analysis.
            throw new NotImplementedException();
        }

        public TResult Execute<TResult> (System.Linq.Expressions.Expression expression)
        {
            return default(TResult);// Strongly typed data set
        }

        public object Execute(System.Linq.Expressions.Expression expression)
        {
            return new List<object> ();// Weakly typed data set}}Copy the code

Let’s see how it works;

using (DbQuery<Order> dbquery = new DbQuery<Order>()) 
{ 
    var OrderList = from order in dbquery where order.OrderName == "111" select order; 
    OrderList.Provider.Execute<List<Order>>(OrderList.Expression);// Execute immediately
    foreach (var o in OrderList) 
    { 
        // Delay execution}}Copy the code

Those of you who enjoy writing ORM frameworks are well worth the time TO create your own LINQ TO ORM, just TO keep you entertained.