EntityFramework dynamic multi-condition query and Lambda Expression Tree, entityframework6

Source: Internet
Author: User

EntityFramework dynamic multi-condition query and Lambda Expression Tree, entityframework6

In conventional information systems, we need dynamic multi-condition queries. For example, there are multiple options on the UI for users to select multiple conditions to query data.
So under the Entity Framework of. net platform, how can we implement it using the Lambda Expression Tree? Here we need a UML class diagram of PredicateBuilder:

/// <Summary>

    /// Enables the efficient, dynamic composition of query predicates.
    /// </summary>
    public static class PredicateBuilder
    {
        /// <summary>
        /// Creates a predicate that evaluates to true.
        /// </summary>
        public static Expression<Func<T, bool>> True<T>() { return param => true; }
 
        /// <summary>
        /// Creates a predicate that evaluates to false.
        /// </summary>
        public static Expression<Func<T, bool>> False<T>() { return param => false; }
 
        /// <summary>
        /// Creates a predicate expression from the specified lambda expression.
        /// </summary>
        public static Expression<Func<T, bool>> Create<T>(Expression<Func<T, bool>> predicate) { return predicate; }
 
        /// <summary>
        /// Combines the first predicate with the second using the logical "and".
        /// </summary>
        public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
        {
            return first.Compose(second, Expression.AndAlso);
        }
 
        /// <summary>
        /// Combines the first predicate with the second using the logical "or".
        /// </summary>
        public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
        {
            return first.Compose(second, Expression.OrElse);
        }
 
        /// <summary>
        /// Negates the predicate.
        /// </summary>
        public static Expression<Func<T, bool>> Not<T>(this Expression<Func<T, bool>> expression)
        {
            var negated = Expression.Not(expression.Body);
            return Expression.Lambda<Func<T, bool>>(negated, expression.Parameters);
        }
 
        /// <summary>
        /// Combines the first expression with the second using the specified merge function.
        /// </summary>
        static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge)
        {
            // zip parameters (map from parameters of second to parameters of first)
            var map = first.Parameters
                .Select((f, i) => new { f, s = second.Parameters[i] })
                .ToDictionary(p => p.s, p => p.f);
 
            // replace parameters in the second lambda expression with the parameters in the first
            var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);
 
            // create a merged lambda expression with parameters from the first expression
            return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);
        }
 
        /// <summary>
        /// ParameterRebinder
        /// </summary>
        class ParameterRebinder : ExpressionVisitor
        {
            /// <summary>
            /// The ParameterExpression map
            /// </summary>
            readonly Dictionary<ParameterExpression, ParameterExpression> map;
 
            /// <summary>
            /// Initializes a new instance of the <see cref="ParameterRebinder"/> class.
            /// </summary>
            /// <param name="map">The map.</param>
            ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map)
            {
                this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();
            }
 
            /// <summary>
            /// Replaces the parameters.
            /// </summary>
            /// <param name="map">The map.</param>
            /// <param name="exp">The exp.</param>
            /// <returns>Expression</returns>
            public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp)
            {
                return new ParameterRebinder(map).Visit(exp);
            }
 
            /// <summary>
            /// Visits the parameter.
            /// </summary>
            /// <param name="p">The p.</param>
            /// <returns>Expression</returns>
            protected override Expression VisitParameter(ParameterExpression p)
            {
                ParameterExpression replacement;
 
                if (map.TryGetValue(p, out replacement))
                {
                    p = replacement;
                }
 
                return base.VisitParameter(p);
            }
        }
    }


UnitTest code snippet, a product query scenario:

            var myProduct=pr.Repository.Find(
                  BuildFindByAllQuery(productName, beignUpdateDate, endUpdateDate) ,
                e => e.UpdatedTime,
                pageIndex,
                pageSize);
 
            Assert.IsTrue(myProduct.Count>0);

UnitTest uses a private method to generate query conditions:

         /// <summary>
         /// Builds the find by all query.
         /// </summary>
         private static Expression<Func<Product, bool>> BuildFindByAllQuery(string productName,DateTime? beignUpdateDate, DateTime? endUpdateDate)
         {
 
             var list = new List<Expression<Func<Product, bool>>>();
 
             if (!string.IsNullOrEmpty(productName)) list.Add(c => c.ProductName == productName);
 
             if (beignUpdateDate != null) list.Add(c => c.UpdatedTime >= beignUpdateDate);
 
             if (endUpdateDate != null) list.Add(c => c.UpdatedTime <= endUpdateDate);
 
             //Add more condition
             Expression<Func<Product, bool>> productQueryTotal = null;
 
             foreach (var expression in list)
             {
                 productQueryTotal = expression.And(expression);
             }
             return productQueryTotal;
         }

The above method consists of three conditions dynamically. One is to match productName, and the other two are beginUpdateDate and endUpdateDate. when determining whether they are last, construct the final query condition set.

Finally, pass the result to a Repository class to complete the corresponding data access.

Is it easy? I hope it will be helpful for your software development.

Articles you may be interested in:

Recursive Method in Expression Tree
Extended method of IEnumerable

Use the LINQ recursive algorithm in. net3.5 to implement concise code

If you want to learn more about software development, please pay attention to my subscription number:


Author: Petter Liu
Source: http://www.cnblogs.com/wintersun/
The copyright of this article is shared by the author and the blog Park. You are welcome to repost this article. However, you must retain this statement without the author's consent and provide a clear link to the original article on the article page. Otherwise, you will be held legally liable.
This article is also published in Petter Liu Blog, my independent Blog.


Net lambda Expression Tree

There is a class named Dynamic. cs, which is open-source by Microsoft. You can search it online. Its running example is as follows:
Var query = db. MERs. where ("City = @ 0 and Orders. count> = @ 1 "," London ", 10 ). orderBy ("CompanyName "). select ("New (CompanyName as Name, Phone )");

How to build a NET Entity Framework distributed application system Framework

To. net FrameWork 3.5 sp1, Entity FrameWork is launched. Different providers can be implemented to support different databases. (Of course, Microsoft still only has built-in SQL Server Provider and other database providers, third-party development is required ). EF and linq. This is. net development ,. net programmers operate data in object mode and query data in programs using SQL-like syntax, which greatly reduces the tedious work of constructing SQL statements and can focus more on writing business logic code. However, in a distributed application system with multiple layers of architecture, when entity objects are remotely serialized to the client, these entities are separated from their data context (that is, the object container, the client cannot directly query entities and perform CUD (Create, Update, Delete) operations. The following uses SQL Server as the database, Remoting + Entity Framework3.5 as the data service layer, and WinForm as the client, describes how to use the EF framework to build a multi-layer distributed application system. Ii. Technical Analysis 1. objects transmitted through a remote client are in the separated State (the attribute value of EntityState is Detached). Therefore, when the server in a multi-tier application updates or deletes an object, the key is how to append an object to an object container. On MSDN, queries for separated entities and CUD operations are described as follows: 1) When an additional object (Entity Framework) executes a query within an object context of the object framework, the returned object is automatically appended to the object context. You can also attach objects obtained from the source rather than from the query to the object context. You can append objects that were previously separated, objects returned by NoTracking queries, or objects obtained from outside the object context. You can also append objects stored in the view State of ASP. NET applications or objects returned from remote method calls or Web services. Use one of the following methods to attach an object to the object context: · call AddObject on ObjectContext to append the object to the object context. This method is used when the object is a new object that does not exist in the data source. · Call Attach on ObjectContext to append the object to the object context. This method is used when the object already exists in the data source but is not currently attached to the context. For more information, see How to: attach related objects (Object framework ). · Call AttachTo of ObjectContext to attach an object to a specific object set in the object context. You can also perform this operation if the object has a null (Nothing in Visual Basic) EntityKey value. · Call ApplyPropertyChanges on ObjectContext. This method is used when the object already exists in the data source and the detached object has the attributes you want to save for updating. If this object is simply appended, the property changes will be lost. For more information, see How to: Apply changes to separated objects (Entity Framework ). 2) View Code2., the sample code of the application's changes to the separated objects (Entity Framework), implements dynamic condition query. In the local environment, we can dynamically construct a Lambda Expression Tree for dynamic condition query for Linq. However, in a remote environment, Lamdba expressions do not support remote serialization and transmission, it can only be implemented through the CreateQuery method of ObjectContext. Fortunately, Microsoft later provided a Dynamic query extension library named Dynamic. cs is more convenient to use, so it is used for implementation. 3. In EF, the core abstract class is ObjectContext, which is derived from the object container. the CUD method on the object container is actually implemented by calling the CUD operation method of ObjectContext. 1) AddObject (string, object): Indicates adding an object to the object container. If the EntityKey value of the object is null, no matter whether it is... the remaining full text>

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.