使用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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...