国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

細說 Fireasy Entity Linq解析的幾個獨創之處

2019-11-17 02:28:10
字體:
來源:轉載
供稿:網友

細說 Fireasy Entity Linq解析的幾個獨創之處

Fireasy Entity的linq內核解析是參考自iqtoolkit源碼的,作者熟讀源碼并吸收其博大精深的思想后,結合項目中的一些需求,對它進行了幾處改進。

一、邏輯刪除標記

做管理系統的開發者可能會習慣于對數據做邏輯刪除處理,即將數據打這一個標記,查詢的時候將這些數據過濾掉。在Fireasy Entity的元數據定義PRopertyMapInfo類中,有IsDeletedKey這樣一個屬性,表示使用此列作為邏輯刪除標記。對應的,在查詢數據的時候,需要把這個標記拼到LINQ里去,不然每次都要這樣的條件,多麻煩:

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

我的做法是,定義一個FakeDeleteFlagRewriter類,對表達式進行重寫,將具有IsDeletedKey屬性的字段等于0的條件加進去。

namespace Fireasy.Data.Entity.Linq.Translators{    /// <summary>    /// 用于為具有假刪除標記的查詢表達式添加標記條件。    /// </summary>    public class FakeDeleteFlagRewriter : DbExpressionVisitor    {        private ColumnExpression fakeColumn;        public static Expression Rewrite(Expression expression)        {            return new FakeDeleteFlagRewriter().Visit(expression);        }        /// <summary>        /// 訪問 <see cref="SelectExpression"/>。        /// </summary>        /// <param name="select">要訪問的表達式。</param>        /// <returns></returns>        protected override Expression VisitSelect(SelectExpression select)        {            if (select.From != null && select.From.NodeType == (ExpressionType)DbExpressionType.Table)            {                var table = (TableExpression)select.From;                //首先要找到具有假刪除標記的列表達式                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>        /// 訪問 <see cref="ColumnExpression"/>。        /// </summary>        /// <param name="column">要訪問的表達式。</param>        /// <returns></returns>        protected override Expression VisitColumn(ColumnExpression column)        {            //記錄下具有假刪除標記的列表達式。            if (fakeColumn == null && column.MapInfo != null && column.MapInfo.IsDeletedKey)            {                fakeColumn = column;            }            return column;        }    }}

這樣,在使用查詢的時候,再不也需要考慮有沒有忘記寫DelFlag == 0了,是不是很方便。

二、對Join表達式中一端具有Group謂詞的改進

某天,發現一個有趣的問題,我需要join一個先被Group后的序列,在join的on條件中,使用到了IGrouping<,>中的Key屬性,問題來了,Key不能被識別,怎么辦?

            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                        });            }

其實不難發現,只要將Key替換成Group語句中的KeySelector就可以了,并且還要考慮keySelector為匿名對象的情況。

一樣的,定義一個GroupKeyReplacer類,對表達式進行重寫。

namespace Fireasy.Data.Entity.Linq.Translators{    /// <summary>    /// 如果 <see cref="JoinExpression"/> 表達式中的一邊具有 Group 子表,則需要將連接條件中的 Key 表達式替換為相應的 <see cref="ColumnExpression"/> 對象。    /// </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 base.VisitNew(newExp);        }        protected override Expression VisitColumn(ColumnExpression column)        {            if (member != null && (member.Name == "Key" || member.Name == column.Name))            {                finder = column;            }            return column;        }    }}

在QueryBinder類中找到BindJoin方法,修改原來的代碼,應用GroupKeyReplacer重寫表達式:

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

三、實體All的擴展

相信大家在使用Select謂詞的時候都有這樣的感觸,如果要加一個屬性返回,是不是要把實體類的大部分屬性全列出來,實體屬性少點還好,太多了會不會漏了某一個屬性。

        [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();        }

這只是一個簡單的示例,現實業務中,這個實體要返回的屬性可能不止這幾個,我一直在想,如果可以把這么繁瑣的工作省略去那該多好。其實仔細的想一想,那也容易辦到。

對IEntity(所有的實體類型都實現了IEntity)擴展一個All方法:

        /// <summary>        /// 返回實體的所有屬性,以及 <paramref name="selector"/> 表達式中的字段。        /// </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;        }

在QueryBinder類里增加一個BindAllFields方法,如下:

        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 Express
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 龙泉市| 搜索| 浦北县| 克拉玛依市| 新丰县| 曲麻莱县| 宁阳县| 桐柏县| 济南市| 沙雅县| 土默特左旗| 图木舒克市| 饶阳县| 鸡泽县| 达拉特旗| 临清市| 集贤县| 开鲁县| 海淀区| 谷城县| 兴国县| 晋江市| 镇赉县| 南部县| 绥滨县| 龙海市| 平舆县| 宜州市| 高雄县| 公主岭市| 达拉特旗| 化德县| 富裕县| 荆门市| 余江县| 邹平县| 监利县| 石棉县| 石楼县| 怀化市| 平利县|