Let's take a closer look at some of the unique features of Fireasy Entity Linq parsing.

Source: Internet
Author: User

Let's take a closer look at some of the unique features of Fireasy Entity Linq parsing.

The linq kernel parsing of Fireasy Entity is based on the source code of iqtoolkit. After carefully reading the source code and absorbing its profound and profound ideas, the author makes several improvements based on some project requirements.

 

I. Logic deletion mark

Developers of management systems may be used to logically deleting data, marking the data and filtering out the data during query. In the Fireasy Entity metadata definition PropertyMapInfo class, an attribute such as IsDeletedKey indicates that this column is used as the logical deletion tag. Correspondingly, when querying data, you need to put this tag into the LINQ, otherwise such a condition will be required each time, which is troublesome:

var list = db.Customers.Where(c => c.DelFlag == 0);

My practice is to define a FakeDeleteFlagRewriter class, rewrite the expression, and add the condition that the field with the IsDeletedKey attribute is equal to 0.

Namespace Fireasy. Data. Entity. Linq. Translators {// <summary> // Add a tag condition to a query expression with a false deletion tag. /// </Summary> public class FakeDeleteFlagRewriter: DbExpressionVisitor {private ColumnExpression fakeColumn; public static Expression Rewrite (Expression expression) {return new FakeDeleteFlagRewriter (). visit (expression) ;}/// <summary> /// access <see cref = "SelectExpression"/>. /// </Summary> /// <param name = "select"> the expression to be accessed. </Param> // <returns> </returns> protected override Expression VisitSelect (SelectExpression select) {if (select. From! = Null & select. from. nodeType = (ExpressionType) DbExpressionType. table) {var table = (TableExpression) select. from; // first, you must find the column expression foreach (var column in select. columns) {base. visit (column. expression);} if (fakeColumn! = Null & fakeColumn. alias. equals (table. alias) {var where = select. where; var condExp = fakeColumn. equal (Expression. constant (0. toType (fakeColumn. type); return select. update (select. from, where! = Null? Expression. and (where, condExp): condExp, select. orderBy, select. groupBy, select. skip, select. take, select. segment, select. isDistinct, select. columns, select. isReverse) ;}} else if (select. from! = Null) {var from = base. visit (select. from); return select. update (from, select. where, select. orderBy, select. groupBy, select. skip, select. take, select. segment, select. isDistinct, select. columns, select. isReverse);} return select;} // <summary> // access <see cref = "ColumnExpression"/>. /// </Summary> /// <param name = "column"> the expression to be accessed. </Param> // <returns> </returns> protected override Expression VisitColumn (ColumnExpression column) {// record the column Expression with the false deletion mark. If (fakeColumn = null & column. MapInfo! = Null & column. MapInfo. IsDeletedKey) {fakeColumn = column;} return column ;}}}

In this way, when using the query, you do not need to consider whether to forget to write DelFlag = 0, is it very convenient.

 

2. Improvement of Group predicates on one end of Join expressions

One day, I found an interesting problem. I need to join a sequence that is first grouped and use the Key attribute in IGrouping <,> IN THE on condition of join, key cannot be identified. What should I do?

            using (var context = new DbContext())            {                var group = context.ZjPayments                    .GroupBy(s => s.GcConId)                    .Select(s => new                        {                            s.Key,                            PaymentMoney = s.Sum(o => o.PaymentMoney),                            PaymentCount = s.Count()                        });                var list = context.ConLists                    .Where(s => s.ItemId == itemId)                    .Segment(pager)                    .OrderBy(sorting, u => u.OrderBy(t => t.SignDate))                    .Join(group.DefaultIfEmpty(), s => s.Id, s => s.Key, (s, t) => new                        {                            s.Id,                            s.SectId,                            s.SectName,                            s.ConName,                            s.ConMoney,                            t.PaymentCount,                            t.PaymentMoney                        });            }

In fact, it is not difficult to find that you only need to replace the Key with the KeySelector in the Group statement and consider the keySelector as an anonymous object.

Define a GroupKeyReplacer class to overwrite the expression.

Namespace Fireasy. data. entity. linq. translators {// <summary> /// if one side of the <see cref = "JoinExpression"/> expression has a Group subtable, replace the Key expression in the connection condition with the corresponding <see cref = "ColumnExpression"/> object. /// </Summary> public class GroupKeyReplacer: DbExpressionVisitor {private MemberInfo member = null; private Expression finder = null; public static Expression Replace (Expression expression) {var replacer = new GroupKeyReplacer (); replacer. visit (expression); return replacer. finder ?? Expression;} protected override Expression VisitMember (MemberExpression memberExp) {if (member = null) {member = memberExp. member;} Visit (memberExp. expression); return memberExp;} protected override Expression VisitNew (NewExpression newExp) {if (newExp. type. isGenericType & newExp. type. getGenericTypeDefinition () = typeof (Grouping <,>) {Visit (newExp. arguments [0]); return newExp;} return B Ase. VisitNew (newExp);} protected override Expression VisitColumn (ColumnExpression column) {if (member! = Null & (member. Name = "Key" | member. Name = column. Name) {finder = column;} return column ;}}}

Find the BindJoin method in the QueryBinder class, modify the original code, and apply the GroupKeyReplacer rewrite expression:

            var outerKeyExpr = GroupKeyReplacer.Replace(Visit(outerKey.Body));            var innerKeyExpr = GroupKeyReplacer.Replace(Visit(innerKey.Body));

 

Iii. Object All extension

I believe you have such feelings when using the Select predicate. If you want to add an attribute to return, do you want to list all the attributes of the object class? It's better to have fewer entity attributes, if there are too many, will a certain attribute be missed.

        [TestMethod]        public void TestAllColumns()        {            var list = db.Orders.Select(s => new                {                    s.CustomerID,                    s.EmployeeID,                    s.OrderID,                    s.OrderDate,                    s.Freight,                    ShortName = s.Customers.CompanyName.Substring(0, 1)                }).ToList();        }

This is just a simple example. In real business, there may be more than these attributes to be returned by this entity. I have been wondering how nice it would be to omit such tedious work. In fact, it is easy to think about it.

Extend the All method to IEntity (IEntity is implemented for All object types:

/// <Summary> /// return all attributes of the object and fields in the <paramref name = "selector"/> expression. /// </Summary> /// <typeparam name = "T"> </typeparam> /// <param name = "entity"> </param> /// <param name = "selector"> </param> // <returns> </returns> public static dynamic All (this IEntity entity, expression <Func <object, object> selector) {return null ;}

Add a BindAllFields method to the QueryBinder class as follows:

        public Expression BindAllFields(Expression source, LambdaExpression selector)        {            if (selector.Body.NodeType != ExpressionType.New)            {                throw new ArgumentException(SR.GetString(SRKind.MustBeNewExpression));            }            var newExp = (NewExpression)Visit(selector.Body);            var arguments = newExp.Arguments.ToList();            var members = newExp.Members.ToList();            foreach (var property in PropertyUnity.GetPersistentProperties(source.Type))            {                var columnExp = new ColumnExpression(property.Type, __alias, property.Name, property.Info);                arguments.Add(columnExp);                members.Add(property.Info.ReflectionInfo);            }            var keyPairArray = new Expression[members.Count];            var constructor = typeof(KeyValuePair<string, object>).GetConstructors()[0];            for (var i = 0; i < members.Count; i++ )            {                keyPairArray[i] = Expression.New(constructor, Expression.Constant(members[i].Name), Expression.Convert(arguments[i], typeof(object)));            }            var arrayExp = Expression.NewArrayInit(typeof(KeyValuePair<string, object>), keyPairArray);            return Expression.Convert(arrayExp, typeof(DynamicExpandoObject));        }

In this way, the query statement can be written like this, saving the effort:

        [TestMethod]        public void TestAllColumns()        {            var list = db.Orders.Select(s => s.All(t => new                {                    ShortName = s.Customers.CompanyName.Substring(0, 1)                }));        }

However, note that after the All method is used, the object will become a dynamic type. The sequence element contains both the attributes of Order and ShortName.

Related Article

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.