使用Asp.Net Core MVC 開發項目實踐[第四篇:基於EF Core的擴展2]

来源:https://www.cnblogs.com/51core/archive/2019/02/25/10431025.html
-Advertisement-
Play Games

上篇我們說到了基於EFCore的基礎擴展,這篇我們講解下基於實體結合拉姆達表達式的自定義更新以及刪除數據. 先說下原理:其實通過實體以及拉姆達表達式生成SQL語句去執行 第一種更新擴展: 自定義更新欄位以及自定義擴展條件,請看下麵的代碼 從上面的方法中我們看到幾個參數,第一個參數不必說,擴展方法第一 ...


上篇我們說到了基於EFCore的基礎擴展,這篇我們講解下基於實體結合拉姆達表達式的自定義更新以及刪除數據.

先說下原理:其實通過實體以及拉姆達表達式生成SQL語句去執行

第一種更新擴展:

自定義更新欄位以及自定義擴展條件,請看下麵的代碼

 1         /// <summary>
 2         /// 自定義更新擴展
 3         /// </summary>
 4         /// <typeparam name="TEntity"></typeparam>
 5         /// <param name="context"></param>
 6         /// <param name="fields">更新欄位</param>
 7         /// <param name="predicate">更新條件</param>
 8         /// <returns></returns>
 9         public static bool MangoUpdate<TEntity>(this DbContext context, Expression<Func<TEntity, bool>> fields, Expression<Func<TEntity, bool>> predicate) where TEntity : class, new()
10         {
11             TSqlAssembledResult result = TSqlAssembled.Update<TEntity>(fields, predicate);
12             context.Database.ExecuteSqlCommand(result.SqlStr);
13             return context.SaveChanges() > 0 ? true : false;
14         }

從上面的方法中我們看到幾個參數,第一個參數不必說,擴展方法第一個參數必須要的,我們重點講清楚一下第二個和第三個參數.

參數:

Expression<Func<TEntity, bool>> fields 

表示實體中需要更新的欄位,這裡的參數要求的是一個拉姆達表達式,如下麵的代碼:

m => m.ClickCount == m.ClickCount + 1

這裡就是更新欄位ClickCount+1的功能.

參數:

Expression<Func<TEntity, bool>> predicate

表示更新條件,這個參數也是一個拉姆達表達式,如下麵代碼:

m => m.NavigationId == navigationId

這裡表示更新條件 NavigationId指定值的資料庫記錄.

接下來我們看方法中的調用

 TSqlAssembled.Update<TEntity>(fields, predicate);

這個方法表示將參數解析成SQL語句,我們看看這個方法的具體內容:

 1         /// <summary>
 2         /// 更新語句組裝
 3         /// </summary>
 4         /// <typeparam name="TEntity"></typeparam>
 5         /// <param name="fields"></param>
 6         /// <param name="predicate"></param>
 7         /// <returns></returns>
 8         public static TSqlAssembledResult Update<TEntity>(Expression<Func<TEntity, bool>> fields, Expression<Func<TEntity, bool>> predicate) where TEntity : class, new()
 9         {
10             try
11             {
12                 StringBuilder strBuilder = new StringBuilder();
13                 strBuilder.Append("update ");
14                 strBuilder.Append(typeof(TEntity).Name);
15                 strBuilder.Append(" set ");
16                 //解析需要更新的欄位值
17                 UpdateFieldBuilder updateFieldBuilder = new UpdateFieldBuilder();
18                 strBuilder.Append(updateFieldBuilder.Translate(fields));
19                 //解析條件
20                 ConditionBuilder conditionBuilder = new ConditionBuilder();
21                 strBuilder.Append(" where ");
22                 strBuilder.Append(conditionBuilder.Translate(predicate));
23                 //處理結果返回
24                 TSqlAssembledResult result = new TSqlAssembledResult();
25                 result.SqlParameters = null;
26                 result.SqlStr = strBuilder.ToString();
27                 return result;
28             }
29             catch(Exception ex)
30             {
31                 return null;
32                 throw ex;
33             }
34         }

PS:這個方法中用到的條件編譯類以及欄位編輯類我們將在文章底部貼出來.

第二種更新擴展:

        /// <summary>
        /// 自定義更新擴展
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="context"></param>
        /// <param name="entity">更新實體</param>
        /// <param name="predicate">更新條件</param>
        /// <returns></returns>
        public static bool MangoUpdate<TEntity>(this DbContext context, TEntity entity, Expression<Func<TEntity, bool>> predicate) where TEntity:class,new()
        {
            TSqlAssembledResult result = TSqlAssembled.Update<TEntity>(entity, predicate);
            context.Database.ExecuteSqlCommand(result.SqlStr, result.SqlParameters);
            return context.SaveChanges() > 0 ? true : false;
        }

參數 TEntity entity表示需要更新的實體

參數 Expression<Func<TEntity, bool>> predicate 表示更新條件,示例如下:

m => m.NavigationId == navigationId

TSqlAssembled.Update<TEntity>(entity, predicate) 這個方法表示將參數解析成SQL語句,我們看看這個方法的具體內容:

        /// <summary>
        /// 更新語句組裝
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="entity"></param>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public static TSqlAssembledResult Update<TEntity>(TEntity entity, Expression<Func<TEntity, bool>> predicate) where TEntity : class, new()
        {
            try
            {
                StringBuilder strBuilder = new StringBuilder();
                strBuilder.Append("update ");
                //
                Type type = entity.GetType();
                strBuilder.Append(type.Name);
                strBuilder.Append(" set ");
                //處理實體類屬性
                PropertyInfo[] properties = type.GetProperties();
                int index = 0;
                List<SqlParameter> sqlParameter = new List<SqlParameter>();
                foreach (var property in properties)
                {
                    object value = property.GetValue(entity, null);
                    if (value != null)
                    {
                        if (index != 0)
                        {
                            strBuilder.Append(",");
                        }
                        strBuilder.Append(property.Name);
                        strBuilder.Append("=@");
                        strBuilder.Append(property.Name);

                        sqlParameter.Add(new SqlParameter(property.Name, value));
                        index++;
                    }
                }
                //編譯條件
                ConditionBuilder conditionBuilder = new ConditionBuilder();
                strBuilder.Append(" where ");
                strBuilder.Append(conditionBuilder.Translate(predicate));
                //處理結果返回
                TSqlAssembledResult result = new TSqlAssembledResult();
                result.SqlParameters = sqlParameter.ToArray();
                result.SqlStr = strBuilder.ToString();
                return result;
            }
            catch (Exception ex)
            {
                return null;
                throw ex;
            }
        }

PS:這裡我們多了將實體反射獲取需要更新的欄位以及欄位值.

第三種刪除擴展:

自定刪除條件,代碼如下

 1         /// <summary>
 2         /// 自定義刪除擴展
 3         /// </summary>
 4         /// <typeparam name="TEntity"></typeparam>
 5         /// <param name="context"></param>
 6         /// <param name="predicate">刪除條件</param>
 7         /// <returns></returns>
 8         public static bool MangoRemove<TEntity>(this DbContext context,Expression<Func<TEntity, bool>> predicate) where TEntity : class,new()
 9         {
10             TSqlAssembledResult result = TSqlAssembled.Delete<TEntity>(predicate);
11             context.Database.ExecuteSqlCommand(result.SqlStr);
12             return context.SaveChanges() > 0 ? true : false;
13         }

參數Expression<Func<TEntity, bool>> predicate表示為自定義條件,示例如下:

_dbContext.MangoRemove<Entity.m_PostsAnswerRecords>(m => m.AnswerId == model.AnswerId && m.UserId == model.UserId);

PS:此段代碼表示根據指定條件刪除m_PostsAnswerRecords表中的記錄

TSqlAssembled.Delete<TEntity>(predicate)方法負責將指定條件編譯成SQL語句,代碼如下:

        /// <summary>
        /// 刪除語句組裝
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public static TSqlAssembledResult Delete<TEntity>(Expression<Func<TEntity, bool>> predicate) where TEntity:class,new()
        {
            try
            {
                string tableName = typeof(TEntity).Name;
                //條件編譯
                ConditionBuilder conditionBuilder = new ConditionBuilder();
                string conditionStr = conditionBuilder.Translate(predicate);
                StringBuilder strBuilder = new StringBuilder();
                strBuilder.Append("delete from ");
                strBuilder.Append(tableName);
                strBuilder.Append(" where ");
                strBuilder.Append(conditionStr);
                //處理結果返回
                TSqlAssembledResult result = new TSqlAssembledResult();
                result.SqlParameters = null;
                result.SqlStr = strBuilder.ToString();
                return result;
            }
            catch(Exception ex)
            {
                throw ex;
            }
        }

下麵我們貼出欄位以及條件的拉姆達表達式解析類:

條件解析類(ConditionBuilder):

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Text;
  4 using System.Linq;
  5 using System.Linq.Expressions;
  6 using System.Reflection;
  7 namespace Mango.Framework.EFCore
  8 {
  9     public class ConditionBuilder : ExpressionVisitor
 10     {
 11 
 12         StringBuilder strBuilder;
 13 
 14         public ConditionBuilder()
 15         {
 16         }
 17 
 18         public string Translate(Expression expression)
 19         {
 20             this.strBuilder = new StringBuilder();
 21             this.Visit(expression);
 22             return this.strBuilder.ToString();
 23         }
 24 
 25         private static Expression StripQuotes(Expression e)
 26         {
 27             while (e.NodeType == ExpressionType.Quote)
 28             {
 29                 e = ((UnaryExpression)e).Operand;
 30             }
 31             return e;
 32         }
 33 
 34         protected override Expression VisitBinary(BinaryExpression b)
 35         {
 36             strBuilder.Append("(");
 37             this.Visit(b.Left);
 38             switch (b.NodeType)
 39             {
 40                 case ExpressionType.AndAlso:
 41                     strBuilder.Append(" and ");
 42                     break;
 43                 case ExpressionType.OrElse:
 44                     strBuilder.Append(" or ");
 45                     break;
 46                 case ExpressionType.Equal:
 47                     strBuilder.Append(" = ");
 48                     break;
 49                 case ExpressionType.NotEqual:
 50                     strBuilder.Append(" <> ");
 51                     break;
 52                 case ExpressionType.LessThan:
 53                     strBuilder.Append(" < ");
 54                     break;
 55                 case ExpressionType.LessThanOrEqual:
 56                     strBuilder.Append(" <= ");
 57                     break;
 58                 case ExpressionType.GreaterThan:
 59                     strBuilder.Append(" > ");
 60                     break;
 61                 case ExpressionType.GreaterThanOrEqual:
 62                     strBuilder.Append(" >= ");
 63                     break;
 64                 default:
 65                     throw new NotSupportedException(string.Format("運算符{0}不支持", b.NodeType));
 66             }
 67             if (b.Right.NodeType != ExpressionType.Parameter&& b.Right.NodeType == ExpressionType.MemberAccess)
 68             {
 69                 LambdaExpression lambda = Expression.Lambda(b.Right);
 70                 var fn = lambda.Compile();
 71                 this.Visit(Expression.Constant(fn.DynamicInvoke(null), b.Right.Type));
 72             }
 73             else
 74             { 
 75                 this.Visit(b.Right);
 76             }
 77             strBuilder.Append(")");
 78             return b;
 79         }
 80 
 81         protected override Expression VisitConstant(ConstantExpression c)
 82         {
 83             switch (Type.GetTypeCode(c.Value.GetType()))
 84             {
 85                 case TypeCode.Boolean:
 86                     strBuilder.Append(((bool)c.Value) ? 1 : 0);
 87                     break;
 88                 case TypeCode.String:
 89                     strBuilder.Append("'");
 90                     strBuilder.Append(c.Value);
 91                     strBuilder.Append("'");
 92                     break;
 93                 case TypeCode.Object:
 94                     throw new NotSupportedException(string.Format("常量{0}不支持", c.Value));
 95                 default:
 96                     strBuilder.Append(c.Value);
 97                     break;
 98             }
 99             return c;
100         }
101 
102         protected override Expression VisitMember(MemberExpression m)
103         {
104             if (m.Expression != null && m.Expression.NodeType == ExpressionType.Parameter)
105             {
106                 strBuilder.Append(m.Member.Name);
107                 return m;
108             }
109             else if (m.Expression != null && m.Expression.NodeType == ExpressionType.Constant)
110             {
111                 LambdaExpression lambda = Expression.Lambda(m);
112                 var fn = lambda.Compile();
113                 this.Visit(Expression.Constant(fn.DynamicInvoke(null), m.Type));
114                 return m;
115             }
116             throw new NotSupportedException(string.Format("成員{0}不支持", m.Member.Name));
117         }
118     }
119 }

更新欄位解析類(UpdateFieldBuilder):

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Text;
 4 using System.Linq;
 5 using System.Linq.Expressions;
 6 using System.Reflection;
 7 namespace Mango.Framework.EFCore
 8 {
 9     public class UpdateFieldBuilder : ExpressionVisitor
10     {
11         StringBuilder strBuilder;
12         public string Translate(Expression expression)
13         {
14             this.strBuilder = new StringBuilder();
15             this.Visit(expression);
16             return this.strBuilder.ToString();
17         }
18 
19         private static Expression StripQuotes(Expression e)
20         {
21             while (e.NodeType == ExpressionType.Quote)
22             {
23                 e = ((UnaryExpression)e).Operand;
24             }
25             return e;
26         }
27         protected override Expression VisitBinary(BinaryExpression b)
28         {
29             //strBuilder.Append("(");
30             this.Visit(b.Left);
31             switch (b.NodeType)
32             {
33                 case ExpressionType.Equal:
34                     strBuilder.Append("=");
35                     break;
36                 case ExpressionType.AndAlso:
37                     strBuilder.Append(",");
38                     break;
39                 case ExpressionType.Add:
40                     strBuilder.Append("+");
41                     break;
42                 case ExpressionType.Subtract:
43                     strBuilder.Append("-");
44                     break;
45                 default:
46                     throw new NotSupportedException(string.Format("運算符{0}不支持", b.NodeType));
47             }
48             this.Visit(b.Right);
49             //strBuilder.Append(")");
50             return b;
51         }
52 
53         protected override Expression VisitConstant(ConstantExpression c)
54         {
55             switch (Type.GetTypeCode(c.Value.GetType()))
56             {
57                 case TypeCode.Boolean:
58                     strBuilder.Append(((bool)c.Value) ? 1 : 0);
59                     break;
60                 case TypeCode.String:
61                     strBuilder.Append("'");
62                     strBuilder.Append(c.Value);
63                     strBuilder.Append("'");
64                     break;
65                 case TypeCode.Object:
66                     throw new NotSupportedException(string.Format("常量{0}不支持", c.Value));
67                 default:
68                     strBuilder.Append(c.Value);
69                     break;
70             }
71             return c;
72         }
73 
74         protected override Expression VisitMember(MemberExpression m)
75         {
76             if (m.Expression != null && m.Expression.NodeType == ExpressionType.Parameter)
77             {
78                 strBuilder.Append(m.Member.Name);
79                 return m;
80             }
81             throw new NotSupportedException(string.Format("成員{0}不支持", m.Member.Name));
82         }
83     }
84 }

到此本篇章完成,更詳細的代碼請下載源代碼查看.


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 第5章 字元串及正則表達式 5.1 字元串常用操作 在Python開發過程中,為了實現某項功能,經常需要對某些字元串進行特殊處理,如拼接字元串、截取字元串、格式化字元串等。下麵將對Python中常用的字元串操作方法進行介紹。 5.1.1 拼接字元串 使用“+” 運算符可完成對多個字元串的拼接,“+” ...
  • Spark RPC 框架的運行時序是怎樣的呢?讓我們深入到它的源碼裡面去看看~~ ...
  • 實例中,可以通過person中的不同類型的對象來實現不同的方法。 ...
  • 企業微信的支付自從企業號變化為企業微信後,增加了一些支付介面以及對很多介面進行了調整,企業微信的支付處理也是變化了不少,往往有時候碰到不少坑,一步一個腳印趟過來的;企業微信支付是需要結合微信商戶後臺進行處理,有時候也需要設置好商戶平臺的相關處理,才能進行發送紅包、支付到個人等等支付處理。本篇隨筆介紹... ...
  • 錯誤實例一:父類的訪問性低於子類 錯誤實例二:方法的訪問修飾符需要和參數的類型的訪問修飾符一致 類似的問題都是可訪問性不一致造成的,修改訪問修飾符即可。 ...
  • 一、.NET MVC 學習筆記(一)——新建MVC工程 接觸MVC有段時間了,一直想找機會整理一下,可是限於文筆太差,所以一直遲遲羞於下手,想到最近做過的MVC項目也有一些了,花點時間整理一下方便以後工作。 開發環境: VS2015 1. 打開VS2015 2. 點擊【新建項目...】,選擇【ASP ...
  • 今天我來學習泛型,泛型是編程入門學習的基礎類型,從.net誕生2.0開始就出現了泛型,今天我們開始學習泛型的語法和使用。 什麼是泛型? 泛型(generic)是C#語言2.0和通用語言運行時(CLR)的一個新特性。泛型為.NET框架引入了類型參數(type parameters)的概念。類型參數使得 ...
  • var retryTimes = 5; //重試次數 int times = 0; skip: //代碼段開始 //處理邏輯 var result=false ; //處理結果 //..... //處理邏輯 //判斷 處理結果是否成功, 並且 重試次數是否達到上限 (處理成功,不需要重試,或達到上限 ...
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...