Orm框架開發之NewExpression合併問題

来源:https://www.cnblogs.com/arthur3k/archive/2019/01/09/10244293.html
-Advertisement-
Play Games

之前都是看別人寫博客,自己沒有寫博客的習慣.在工作的過程中,總是會碰到許多的技術問題.有很多時候想記錄下來,後面一直有許多的問題等著解決.總想著等系統完成了,再回頭總結下.往往結果就把這事拋到腦後了. 總覺得不能一直這樣哈.今天簡單記一下吧.有表達不清楚的地方,多多包涵. 最近在研究.net orm ...


之前都是看別人寫博客,自己沒有寫博客的習慣.在工作的過程中,總是會碰到許多的技術問題.有很多時候想記錄下來,後面一直有許多的問題等著解決.總想著等系統完成了,再回頭總結下.往往結果就把這事拋到腦後了.

總覺得不能一直這樣哈.今天簡單記一下吧.有表達不清楚的地方,多多包涵.

最近在研究.net orm框架.想開發一套更好用的Orm框架.別嫌輪子多.碰到一個Expression合併的問題.

一.需求情況描述

需要更新部分數據的時候,可能前端傳回的只有部分欄位的數據.而更新的時候,需要設置更新人,更新日期等.

舉個慄子來說:

現在有一個預約信息表

前端需要修改數據內容如下,我們暫且叫表達A

var exp = ExpressionHelper.CreateExpression<AppointmentDto>(a => new {
    a.Id,
    a.PatientName,
    a.PatientNamePy,
    a.IdentityCardNumber,
    a.Birthday,
    a.PatientAge,
    a.PatientSex,
    a.PatientPhone,
    a.Address
});

 

而寫入資料庫的時候需要添加更新人,更新時間.LastUpdateUserId和UpdateTime.

於是我們便又多了一個lambda表達式,我們叫它表達式B

var exp = ExpressionHelper.CreateExpression<AppointmentDto>(a => new {
    a.Id,
    a.PatientName,
    a.PatientNamePy,
    a.IdentityCardNumber,
    a.Birthday,
    a.PatientAge,
    a.PatientSex,
    a.PatientPhone,
    a.Address,
    a.LastUpdateUserId,
    a.UpdateTime
});

這裡說下ExpressionHelper.CreateExpression<T>方法,只是一個為了縮減代碼長度而寫的方法.輸入的lambda表達式原樣返回了.

外面不用寫好長的類型了.Expression這個類型平時不用.寫外面看著眼暈.  Expression<Func<AppointmentDto, object>> exp1 = a => new {a.Id,a.PatientName}; 

/// <summary>
/// 轉換Expr
/// 在外面調用時可以使用var以減少代碼長度
/// </summary>
/// <param name="expr"></param>
/// <returns></returns>
public static Expression<Func<T, object>> CreateExpression<T>(Expression<Func<T, object>> expr)
{
    return expr;
}

所以此處,使用var可以看起來更整潔.但並不推薦在正常情況下使用var.

個人覺得使用var讓代碼可維護性降低.讀起來真的是頭疼.之前在維護一個比較大的系統的時候,公司的主要項目,缺少項目文檔,代碼裡面也基本上沒啥註釋.而且又清一色的var,每個方法返回的是啥類型?你得去方法那邊看去.看著真是惱火,又不得不去一點一點的改.都改成相應的類型後,看著就清爽多了.看一眼,流程就基本上能明白大概.所以,var在C#這種強類型語言里,能不用就別用了.

上面就當是發牢騷了.我們回到正題.

我們看到表達式B比表達式A只多了兩個欄位.大多數代碼都是重覆的.而且,兩個lambda表達式嚴重的加長了代碼行數.幾個這樣的表達式下來,這個類就到了幾百行了.

對於喜歡簡潔,簡單的我來說,類一大了我就頭疼.那咋整?要是有辦法將這兩個表達式簡化處理一下就好了.將表達式A加上一個短的表達式,來實現表達式B呢.

比如實現 var exprB = exprA.Add(a => new { a.PatientPhone }); 

So,開始捯飭...

二.解決方法

因為這個合併表達式的方法是在個人系統內部使用滿足我定製的Orm的類名稱需求

所以定義了一個新的Expression表達式類型NewObjectExpression來處理

  1     /// <summary>
  2     /// New Object Expression
  3     /// 合併NewExpression使用.
  4     /// </summary>
  5     public class NewObjectExpression : Expression, IArgumentProvider
  6     {
  7         private IList<Expression> arguments;
  8 
  9         /// <summary>
 10         /// 構造方法
 11         /// </summary>
 12         /// <param name="constructor"></param>
 13         /// <param name="arguments"></param>
 14         /// <param name="members"></param>
 15         internal NewObjectExpression(ConstructorInfo constructor, IList<Expression> arguments, List<MemberInfo> members)
 16         {
 17             this.Constructor = constructor;
 18             this.arguments = arguments;
 19             this.Members = members;
 20 
 21             if (members != null)
 22             {
 23                 List<string> nameList = members.Select(member => member.Name).ToList();
 24                 for (int i = 0; i < nameList.Count; i++)
 25                 {
 26                     if (!string.IsNullOrEmpty(ExpressionString))
 27                     {
 28                         ExpressionString += "," + nameList[i];
 29                     }
 30                     else
 31                     {
 32                         ExpressionString = nameList[i];
 33                     }
 34                 }
 35             }
 36         }
 37 
 38         /// <summary>
 39         /// Gets the static type of the expression that this <see cref="Expression" /> represents. (Inherited from <see cref="Expression"/>.)
 40         /// </summary>
 41         /// <returns>The <see cref="Type"/> that represents the static type of the expression.</returns>
 42         public override Type Type
 43         {
 44             get { return Constructor.DeclaringType; }
 45         }
 46 
 47         /// <summary>
 48         /// Returns the node type of this <see cref="Expression" />. (Inherited from <see cref="Expression" />.)
 49         /// </summary>
 50         /// <returns>The <see cref="ExpressionType"/> that represents this expression.</returns>
 51         public sealed override ExpressionType NodeType
 52         {
 53             get { return ExpressionType.New; }
 54         }
 55 
 56         /// <summary>
 57         /// Gets the called constructor.
 58         /// </summary>
 59         public ConstructorInfo Constructor { get; }
 60 
 61         /// <summary>
 62         /// Gets the arguments to the constructor.
 63         /// </summary>
 64         public ReadOnlyCollection<Expression> Arguments
 65         {
 66             get { return (ReadOnlyCollection<Expression>)arguments; }
 67         }
 68 
 69         Expression IArgumentProvider.GetArgument(int index)
 70         {
 71             return arguments[index];
 72         }
 73 
 74         int IArgumentProvider.ArgumentCount
 75         {
 76             get
 77             {
 78                 return arguments.Count;
 79             }
 80         }
 81         
 82         /// <summary>
 83         /// ExpressionString
 84         /// </summary>
 85         public string ExpressionString { get; private set; } = "";
 86 
 87         public ConstructorInfo Constructor1 => Constructor;
 88 
 89         public List<MemberInfo> Members { get; set; }
 90 
 91         /// <summary>
 92         /// 更新members
 93         /// </summary>
 94         /// <param name="arguments"></param>
 95         /// <param name="members"></param>
 96         /// <returns></returns>
 97         public NewObjectExpression Update(IList<Expression> arguments, List<MemberInfo> members)
 98         {
 99             if (arguments != null)
100             {
101                 this.arguments = arguments;
102             }
103             if (Members != null)
104             {
105                 this.Members = members;
106                 ExpressionString = "";
107                 List<string> nameList = members.Select(member => member.Name).ToList();
108                 for (int i = 0; i < nameList.Count; i++)
109                 {
110                     if (!string.IsNullOrEmpty(ExpressionString))
111                     {
112                         ExpressionString += "," + nameList[i];
113                     }
114                     else
115                     {
116                         ExpressionString = nameList[i];
117                     }
118                 }                
119             }
120             return this;
121         }
122     }
View Code

待處理的屬性都放到了Members裡面.後面解析使用的也是Members.其它方法Copy自NewExpression的源碼,可以刪了不用.

下麵我們來擴展Expression<Func<T, object>>,讓Expression<Func<T, object>>擁有Add和Remove屬性的方法.

直接上代碼,看前兩個方法.後面兩個方法是擴展Expression<Func<T, bool>>表達式的And和Or.等有回頭有空再介紹.

  1     /// <summary>
  2     /// Expression 擴展
  3     /// </summary>
  4     public static class ExpressionExpand
  5     {
  6         /// <summary>
  7         /// Expression And 
  8         /// NewExpression 合併
  9         /// </summary>
 10         /// <param name="expr"></param>
 11         /// <returns></returns>
 12         public static Expression<Func<T, object>> Add<T>(this Expression<Func<T, object>> expr, Expression<Func<T, object>> expandExpr)
 13         {
 14             Expression<Func<T, object>> result = null;
 15             ParameterExpression parameter = Expression.Parameter(typeof(T), "p");
 16             List<MemberInfo> memberInfoList = new List<MemberInfo>();
 17             #region 處理原expr
 18             if (expr.Body is NewExpression)
 19             {   // t=>new{t.Id,t.Name}
 20                 NewExpression newExp = expr.Body as NewExpression;
 21                 if (newExp.Members != null)
 22                 {
 23                     memberInfoList = newExp.Members.ToList();
 24                 }
 25             }
 26             else if (expr.Body is NewObjectExpression)
 27             {
 28                 NewObjectExpression newExp = expr.Body as NewObjectExpression;
 29                 if (newExp.Members != null)
 30                 {
 31                     memberInfoList = newExp.Members.ToList();
 32                 }
 33             }
 34             else if (expr.Body is UnaryExpression)
 35             {   //t=>t.Id
 36                 UnaryExpression unaryExpression = expr.Body as UnaryExpression;
 37                 MemberExpression memberExp = unaryExpression.Operand as MemberExpression;
 38                 memberInfoList.Add(memberExp.Member);
 39             }
 40             #endregion
 41 
 42             #region 處理擴展expr
 43             if (expandExpr.Body is NewExpression)
 44             {   // t=>new{t.Id,t.Name}
 45                 NewExpression newExp = expandExpr.Body as NewExpression;
 46                 for (int i = 0; i < newExp.Members.Count; i++)
 47                 {
 48                     MemberExpression memberExp = Expression.Property(parameter, newExp.Members[i].Name);
 49                     if (!memberInfoList.Any(member => member.Name == newExp.Members[i].Name))
 50                     {
 51                         memberInfoList.Add(newExp.Members[i]);
 52                     }
 53                 }
 54             }
 55             else if (expr.Body is NewObjectExpression)
 56             {
 57                 NewObjectExpression newExp = expr.Body as NewObjectExpression;
 58                 if (newExp.Members != null && newExp.Members.Count > 0)
 59                 {
 60                     for (int i = 0; i < newExp.Members.Count; i++)
 61                     {
 62                         MemberExpression memberExp = Expression.Property(parameter, newExp.Members[i].Name);
 63                         if (!memberInfoList.Any(member => member.Name == newExp.Members[i].Name))
 64                         {
 65                             memberInfoList.Add(newExp.Members[i]);
 66                         }
 67                     }
 68                 }
 69             }
 70             else if (expandExpr.Body is UnaryExpression)
 71             {   //t=>t.Id
 72                 UnaryExpression unaryExpression = expandExpr.Body as UnaryExpression;
 73                 MemberExpression memberExp = unaryExpression.Operand as MemberExpression;
 74                 if (!memberInfoList.Any(exp => exp.Name == memberExp.Member.Name))
 75                 {
 76                     memberInfoList.Add(memberExp.Member);
 77                 }
 78             }
 79             #endregion
 80             NewObjectExpression newObjExpression = new NewObjectExpression(typeof(object).GetConstructors()[0], null, memberInfoList);
 81             result = Expression.Lambda<Func<T, object>>(newObjExpression, parameter);
 82             return result;
 83         }
 84 
 85         /// <summary>
 86         /// Expression Remove 
 87         /// NewExpression 合併
 88         /// </summary>
 89         /// <param name="expr"></param>
 90         /// <returns></returns>
 91         public static Expression<Func<T, object>> Remove<T>(this Expression<Func<T, object>> expr, Expression<Func<T, object>> expandExpr)
 92         {
 93             Expression<Func<T, object>> result = null;
 94             ParameterExpression parameter = Expression.Parameter(typeof(T), "p");
 95             List<MemberInfo> memberInfoList = new List<MemberInfo>();
 96             List<MemberInfo> removeMemberInfoList = new List<MemberInfo>();
 97             #region 處理原expr
 98             if (expr.Body is NewExpression)
 99             {   // t=>new{t.Id,t.Name}
100                 NewExpression newExp = expr.Body as NewExpression;
101                 if (newExp.Members != null)
102                 {
103                     memberInfoList = newExp.Members.ToList();
104                 }
105             }
106             else if (expr.Body is NewObjectExpression)
107             {
108                 NewObjectExpression newExp = expr.Body as NewObjectExpression;
109                 if (newExp.Members != null)
110                 {
111                     memberInfoList = newExp.Members.ToList();
112                 }
113             }
114             else if (expr.Body is UnaryExpression)
115             {   //t=>t.Id
116                 UnaryExpression unaryExpression = expr.Body as UnaryExpression;
117                 MemberExpression memberExp = unaryExpression.Operand as MemberExpression;
118                 memberInfoList.Add(memberExp.Member);
119             }
120             #endregion
121 
122             #region 處理擴展expr
123             if (expandExpr.Body is NewExpression)
124             {   // t=>new{t.Id,t.Name}
125                 NewExpression newExp = expandExpr.Body as NewExpression;
126                 for (int i = 0; i < newExp.Members.Count; i++)
127                 {
128                     MemberExpression memberExp = Expression.Property(parameter, newExp.Members[i].Name);
129                     if (!removeMemberInfoList.Any(member => member.Name == newExp.Members[i].Name))
130                     {
131                         removeMemberInfoList.Add(newExp.Members[i]);
132                     }
133                 }
134             }
135             else if (expr.Body is NewObjectExpression)
136             {
137                 NewObjectExpression newExp = expr.Body as NewObjectExpression;
138                 if (newExp.Members != null && newExp.Members.Count > 0)
139                 {
140                     for (int i = 0; i < newExp.Members.Count; i++)
141                     {
142                         MemberExpression memberExp = Expression.Property(parameter, newExp.Members[i].Name);
143                         if (!removeMemberInfoList.Any(member => member.Name == newExp.Members[i].Name))
144                         {
145                             removeMemberInfoList.Add(newExp.Members[i]);
146                         }
147                     }
148                 }
149             }
150             else if (expandExpr.Body is UnaryExpression)
151             {   //t=>t.Id
152                 UnaryExpression unaryExpression = expandExpr.Body as UnaryExpression;
153                 MemberExpression memberExp = unaryExpression.Operand as MemberExpression;
154                 if (!memberInfoList.Any(exp => exp.Name == memberExp.Member.Name))
155                 {
156                     removeMemberInfoList.Add(memberExp.Member);
157                 }
158             }
159             #endregion
160 
161             for (int i = memberInfoList.Count - 1; i >= 0; i--)
162             {
163                 if (removeMemberInfoList.Any(member => member.Name == memberInfoList[i].Name))
164                 {
165                     memberInfoList.Remove(memberInfoList[i]);
166                 }
167             }
168             if (memberInfoList.Count <= 0)
169             {
170                 throw new System.Exception("Expression Remove Error.All Properties are removed.");
171             }
172             NewObjectExpression newObjExpression = new NewObjectExpression(typeof(object).GetConstructors()[0], null, memberInfoList);
173             result = Expression.Lambda<Func<T, object>>(newObjExpression, parameter);
174             return result;
175         }
176 
177         /// <summary>
178         /// Expression And
179         /// </summary>
180         /// <param name="expr"></param>
181         /// <returns></returns>
182         public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr, Expression<Func<T, bool>> expandExpr)
183         {
184             Expression<Func<T, bool>> result = Expression.Lambda<Func<T, bool>>(Expression.And(expandExpr.Body, expr.Body), expr.Parameters);
185             return result;
186         }
187 
188         /// <summary>
189         /// Expression And
190         /// </summary>
191         /// <param name="expr"></param>
192         /// <returns></returns>
193         public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr, Expression<Func<T, bool>> expandExpr)
194         {
195             Expression<Func<T, bool>> result = Expression.Lambda<Func<T, bool>>(Expression.Or(expandExpr.Body, expr.Body), expr.Parameters);
196             return result;
197         }
198     }
View Code

Add方法可處理 NewExpression 類似 t=>new{t.Id,t.Name} , UnaryExpression 類似t=>t.Id,以及我們自定義的NewObjectExpression類型

所以我們在更新數據的時候就可以這麼寫了:

Dbc.Db.Update(dto, exp.Add(a => a.LastUpdateUserId));
Dbc.Db.Update(dto, exp.Add(a => new { a.LastUpdateUserId, a.UpdateTime }));

在Orm框架內部,解析NewObjectExpression時,解析方法如下

 1         /// <summary>
 2         /// 通過Lambed Expression獲取屬性名稱
 3         /// </summary>
 4         /// <param name="expr">查詢表達式</param>
 5         /// <returns></returns>
 6         public static List<string> GetPiList<T>(Expression<Func<T, object>> expr)
 7         {
 8             List<string> result = new List<string>();
 9             if (expr.Body is NewExpression)
10             {   // t=>new{t.Id,t.Name}
11                 NewExpression nexp = expr.Body as NewExpression;
12                 if (nexp.Members != null)
13                 {
14                     result = nexp.Members.Select(member => member.Name).ToList();
15                 }
16             }
17             else if (expr.Body is NewObjectExpression)
18             {   // t=>new{t.Id,t.Name}
19                 NewObjectExpression nexp = expr.Body as NewObjectExpression;
20                 if (nexp.Members != null)
21                 {
22                     result = nexp.Members.Select(member => member.Name).ToList();
23                 }
24             }
25             else if (expr.Body is UnaryExpression)
26             {   //t=>t.Id
27                 UnaryExpression uexp = expr.Body as UnaryExpression;
28                 MemberExpression mexp = uexp.Operand as MemberExpression;
29                 result.Add(mexp.Member.Name);
30             }
31             else
32             {
33                 throw new System.Exception("不支持的Select lambda寫法");
34             }
35             return result;
36         }
View Code

至此,就完成了Expression<Func<T, object>>Add和Remove屬性的擴展,Orm可以讓代碼更簡潔.

三.後記

其實在使用新的類NewObjectExpression來解決之前,嘗試過其它的許多方式,因為使用.net的類型可以在其它的框架程式中借鑒引用.不必局限在個人框架內部.

NewExpression內部有一些校驗,本身Expression<Func<T, object>>是一個匿名類.試過處理NewExpression,以及新建類繼承自NewExpression等方式.都沒成功.

要是大家有更好的方法歡迎留言告知.希望本文能對大家有所幫助.

 


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

-Advertisement-
Play Games
更多相關文章
  • 所謂OJ,顧名思義Online Judge,一個用戶提交的程式在Online Judge系統下執行時將受到比較嚴格的限制,包括運行時間限制,記憶體使用限制和安全限制等。用戶程式執行的結果將被Online Judge系統捕捉並保存,然後再轉交給一個裁判程式。該裁判程式或者比較用戶程式的輸出數據和標準輸出 ...
  • 什麼是人工智慧 人工智慧是電腦科學的一個分支,它企圖瞭解智能的實質,並生產出一種新的能以人類智能相似的方式做出反應的智能機器,該領域的研究包括機器人、語言識別、圖像識別、自然語言處理和專家系統等。 我們來談談人工智慧 人工智慧自誕生以來,技術日益成熟,應用領域也在不斷擴大,從我們日常用的智能音箱, ...
  • 一. 概述 介紹asp.net core路由時,我初步想了下,分幾篇來說明。 路由的知識點很多,參考了官方文檔提取出一些重要的知識點來說。 在ASP.NET Core中是使用路由中間件來匹配傳入請求的 URL 並將它們映射到操作(action方法)。路由是在程式啟動時進行傳統路由或屬性路由定義。 路 ...
  • C# 命令行編譯C#程式問題詳解。 在使用命令行編譯C#程式過程中,看似很簡單,實際上遇到了許多問題。我把我踩的坑列出來,希望對踩坑的朋友有所幫助。 步驟如下: 1.Windows+R 打開運行,notepad 打開記事本,添加如下代碼到記事本。 1 using System; 2 using Sy ...
  • ...
  • 1.Convert類型轉換 總結: 類型如果相相容的兩個變數,可以使用自動類型轉換或者強制類型轉換。 但是,如果兩個類型的變數不相容,比如string與int或者string 與double, 這個時候我們可以使用一個叫做Convert的轉換工廠進行轉換。 註意:使用Convert進行類型轉換,也需 ...
  • 清晨起床,震驚了,窗外一片雪白,大雪紛飛,我承認我詞窮了,說再多話也描述不了此刻的大好心情。所以,話不多說,先上一張朋友圈的圖吧! 趁著這麼“好的”天氣以及這麼好的心情突然想寫點東西記錄一下自己的2018這一年以及2019年的這一天以及對.NET Core的看法。 俗話說“瑞雪兆豐年”,其實我想說這 ...
  • 第一種,自己手寫dockerfile發佈,上傳至hubDocker 1. 正常發佈到文件夾中,發佈文件上傳至linux機器上。如 /www/app 2. 將Dockerfile文件也複製到同目錄 。/www/app 3. 輸入 ,構建一個demo名字的鏡像。這個時候就會構建鏡像,輸入 可以查看當剛剛 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...