Share dynamic splicing expression expressions component and principle

Source: Internet
Author: User

Objective

LINQ everyone knows that it's good to use it, but there's a problem when you're searching with LINQ, you write that.

    1. var query = from the user in db. Set<user> ()
    2. where user. Username = = "xxxx"
    3. Select User;

OK, it looks good, but If you want to do a dynamic search, • Oh! In fact, the method is still very much, just around the Big Bend

What is dynamic search? By the way, if you make a table page, there is a user name, registration time, rank three columns, you want to implement dynamic combination search, only when the user specified to search by the user name to add the user name this column to search conditions, the traditional SQL is so dry

    1. string sql= "select * from user ";
    2. if (username!= "")
    3. {
    4. sql+= " Where username=" +username
    5. }

Disclaimer: Just do an example, can not run unimportant! ( the code above must normally be problematic)

Can you do that with LINQ? Uh, To the bottom of this

  1. var query = from the user in db. Set<user> ()
  2. Select User;
  3. var userName = string. Empty;
  4. if (! string. Isnullorwhitespace (UserName))
  5. {
  6. query = query. Where (x = X.username = = Username);
  7. }

Yes, it can be, but in the actual project is generally not directly returned to the IQueryable interface, there is no way to do so.

So, the dynamic splicing LINQ came into being, and the Essence of LINQ is the expression tree, and you can see the signature of the where extension method of IQueryable, which begins with expression.

Introduction and use of components

The original purpose of encapsulation is also for self-use. I'm lazy, so I'm going to make the components as simple as possible, here's a complete example of use

  1. Testdatacontext db = new testdatacontext ();
  2. var builder = new expressionbuilder<user> ();//Instantiate component, User what is said below
  3. var filters = New list<sqlfilter> ();
  4. Filters. ADD (Sqlfilter.create ("Id", operation.equal, 1)); Add a search condition where the user's id attribute value equals 1
  5. Filters. ADD (Sqlfilter.create ("lastlogindate", Operation.greaterthan, DateTime.Now));// Add user's Lastlogindate property value is greater than the current search criteria
  6. Filters. Add (Sqlfilter.create ("Username", Operation.like, "aaaa"));//Adding the user's Username attribute value to the search criteria like "AAAAA"
  7. Filters. Add (Sqlfilter.create ("ID", operation.in, new int[] {1, 2, 3}));//Add user's Id attribute value at 1, 2, 3 search conditions, when operation is in, the last argument must be a collection
  8. Filters. ADD (Sqlfilter.create ("Password", Operation.notequal, "1"));
  9. Filters. ADD (Sqlfilter.create ("Status", operation.in, new int[] {1}));
  10. var where = Builder. Build (filters, new dictionary<string, string> ());//According to the above conditions, splicing out the expression tree
  11. var results = db. Set<user> (). where (where). ToList ();//The Earth people know

The above code is spliced out the expression tree is like this

    1. var ids=new int[]{1,2,3};
    2. var status=new int[]{1};
    3. Db. Set<user> (). Where (x = x.id = = 1 && x.lastlogindate > DateTime.Now && ids. Contains (x.id) && x.username.contains ("aaaa") && X.password! = "1" && status . Contains (X.status));

The comments have been made clear, but lines 2nd and 10th need to be explained in particular, and the build method for line 10th is prototyped as follows

    1. Public Expression<func<tparameter, bool>> Build (ilist<sqlfilter> filters, dictionary< String, string> Filternamemap)

The return value is a expression<func<tparameter,bool>> type, which has a generic parameter, which is the user when the 2nd row is instantiated, and when used, You must ensure that the attributes of each search condition that you add are in the user class.

Why design it like this? This feeling is not clear at once, when the principle is said

In addition, we can see that there is a filternamemap parameter, which is mainly used for the conversion of property names, and is generally used for foreign keys. Let me briefly describe my design intentions at that time.

For example, there is a list that shows role information in the permissions system, with the role name, description, and functionality of the three columns, where the third column is from the menu and the others are from the role table.

In general, the property name of the third column may be set to privileges, and then the type is string, but if the user wants to search by role-owned functionality, you can't filter by string? It is usually filtered by the function ID, also privilegeid.

Because I'm using ExtJS (skip this section directly), so the question is, ExtJS passed me the parameter name is privileges, the value is a collection, because my Model class property name is this, but my background for filtering the real property is Privilegeid, So I need to map privileges to Privilegeid, and tell ExpressionBuilder that if you encounter the search criteria for the privileges attribute name, change the attribute name to Privilegeid for stitching.

To facilitate understanding, the following is the source of Sqlfilter, very simple

  1. Public class Sqlfilter
  2. {
  3. Public Static Sqlfilter Create (string PropertyName, operation operation, object value)
  4. {
  5. return New Sqlfilter ()
  6. {
  7. Name = PropertyName,
  8. Operation = operation,
  9. Value = value
  10. };
  11. }
  12. // <summary>
  13. /// field name
  14. // </summary>
  15. Public string Name { get; set; }
  16. // <summary>
  17. /// search operation, greater than or equal to
  18. // </summary>
  19. Public Xinchen.DbUtils.Operation operation { get; set; }
  20. // <summary>
  21. /// Search parameter values
  22. // </summary>
  23. Public Object Value { get; set; }
  24. }

Here's the operation.

  1. Public enum Operation
  2. {
  3. GreaterThan,
  4. LessThan,
  5. Greaterthanorequal,
  6. Lessthanorequal,
  7. NotEqual,
  8. Equal,
  9. Like,
  10. Inch
  11. }
Component principle

I'm not sure I can say it clearly ...

is actually the principle of splicing the expression tree

  1. //If we want to splice x=>x.id==1, if the type of x is User
  2. var parameterexp = Expression.parameter (typeof(User), "x");
  3. //The result is this: X=>,x is the variable name
  4. var propertyexp = Expression.property (Parameterexp, "Id");
  5. //The result is this: x=>x.id, this sentence is to construct an expression that accesses the property
  6. //The first parameter of the above sentence is the object expression you want to take the property to. We want to spell the expression is x=>x.id==1,==1 this piece first regardless, actually is x=>x.id, then actually we are to take the attribute value to x, and X is Parameterexp, so the first parameter is Parameterexp, the second argument say, is the property name
  7. var constexp = expression.constant (1);
  8. //result is • No result, build a constant expression with a value of 1 (The World of LINQ, Everything is an expression tree)
  9. //Right now is the key step.
  10. var BODY = expression.equal (propertyexp, constexp);
  11. //The result is: X=>x.id==1, this · You need to explain it, it's simple, isn't it? Create an equal expression and pass in the left and right expressions
  12. //Of course it doesn't work here, and it needs to continue.
  13. var lambda = expression.lambda<func<user, bool>> (body, parameterexp);
  14. //This sentence and the second sentence are the most difficult to understand when I learned two places. This is to encapsulate our results into energy, the first parameter is our result, the second parameter is the parameter required to achieve this result, which of course is parameterexp, then the generic parameter func<user,bool> Is that we want to encapsulate this expression into what kind of thing, at this time, the type of lambda is expression<fun<user,bool>>

This is a fairly simple expression tree, and the notes are very well written, and the following is a complex

  1. //If we want to splice x=>x.username.contains ("AAA"), if the type of x is User
  2. var parameterexp = Expression.parameter (typeof(User), "x");
  3. var propertyexp = Expression.property (Parameterexp, "Username");
  4. //The above two sentences are no longer introduced
  5. var containsmethod = typeof(string). GetMethod ("Contains", new type[] { typeof(string)});
  6. //Because we are going to splice an expression that calls the Contains method of the string type username, so the reflection gets the contains method of the string type
  7. var constexp = expression.constant ("aaa");
  8. //no longer explained
  9. var containsexp = Expression.call (Propertyexp, Containsmethod, constexp);
  10. The result is: X=>x.username.contains ("AAA"), the first parameter, which is the method to invoke which instance, here is Propertyexp, the second is which method to call, and the third is the argument, which understands the previous example, This should not be difficult to understand .
  11. var lambda = expression.lambda<func<user, bool>> (Containsexp, parameterexp);
  12. //no longer explained

As you can see, the first sentence takes the user type, so I used generics in the design expressionbuilder for passing this parameter

The principle is here, to see more examples of directly read the source bar

Postscript

Continue advertising ... To understand the relevant technology, please enter QQ group 74522853, the answer XLinq

Share dynamic splicing expression expressions component and principle

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.