模擬EF CodeFist 實現自己的ORM

来源:http://www.cnblogs.com/buruainiaaaa/archive/2017/07/29/7255792.html
-Advertisement-
Play Games

一.什麼是ORM 對象關係映射(Object Relational Mapping,簡稱ORM)模式是一種為瞭解決面向對象與關係資料庫存在的互不匹配的現象的技術。 簡單來說,ORM 是通過使用描述對象和資料庫之間映射的元數據,將程式中的對象自動持久化到關係資料庫中或者將資料庫的數據拉取出來 二.EF ...


一.什麼是ORM

    對象關係映射(Object Relational Mapping,簡稱ORM)模式是一種為瞭解決面向對象與關係資料庫存在的互不匹配的現象的技術。

    簡單來說,ORM 是通過使用描述對象和資料庫之間映射的元數據,將程式中的對象自動持久化到關係資料庫中或者將資料庫的數據拉取出來

二.EF基本原理

 1.EF 是微軟以 ADO.NET 為基礎所發展出來的對象關係對應 (O/R Mapping) 解決方案

 2.EF 核心對象DbContext,其基本原理是,實現系統IQueryable<T>介面,通過反射,獲取SQL語句,操作資料庫

三.模擬EF

1.模擬EF 首先要自定義解析lamdba表達式(解析表達式 是個難點,需要仔細調試)

    1)構造表達式解析入口

       

 1 /// <summary>
 2         /// 通過Lambda解析為Sql
 3         /// </summary>
 4         /// <param name="func"></param>
 5         /// <returns></returns>
 6         public static string GetSqlByExpression(Expression func, DirectionType dirType = DirectionType.None)
 7         {
 8             var getExp = func;
 9             var result = "";
10             if (getExp is UnaryExpression)
11             {
12                 result += VisitUnaryExpression((UnaryExpression)getExp);
13             }
14             if (getExp is BinaryExpression)
15             {
16                 result += VisitBinaryExpression((BinaryExpression)getExp);
17             }
18             if (getExp is TypeBinaryExpression)
19             {
20                 result += VisitTypeBinaryExpression((TypeBinaryExpression)getExp);
21             }
22             if (getExp is ConditionalExpression)
23             {
24                 result += VisitConditionalExpression((ConditionalExpression)getExp);
25             }
26             if (getExp is ConstantExpression)
27             {
28                 result += VisitConstantExpression((ConstantExpression)getExp);
29             }
30             if (getExp is ParameterExpression)
31             {
32                 result += VisitParameterExpression((ParameterExpression)getExp);
33             }
34             if (getExp is MemberExpression)
35             {
36                 result += VisitMemberExpression((MemberExpression)getExp, dirType);
37             }
38             if (getExp is LambdaExpression)
39             {
40                 result += VisitLambdaExpression((LambdaExpression)getExp);
41             }
42             if (getExp is NewExpression)
43             {
44                 result += VisitNewExpression((NewExpression)getExp);
45             }
46             if (getExp is NewArrayExpression)
47             {
48                 result += VisitNewArrayExpression((NewArrayExpression)getExp);
49             }
50             if (getExp is InvocationExpression)
51             {
52                 result += VisitInvocationExpression((InvocationExpression)getExp);
53             }
54             if (getExp is MemberInitExpression)
55             {
56                 result += VisitMemberInitExpression((MemberInitExpression)getExp);
57             }
58             if (getExp is ListInitExpression)
59             {
60                 result += VisitListInitExpression((ListInitExpression)getExp);
61             }
62             if (getExp is MethodCallExpression)
63             {
64                 result += VisitMethodCallExpression((MethodCallExpression)getExp);
65             }
66             return result;
67 
68         }
lamdba解析入口

    2)根據不同的類型,構建不同的解析方法

 /// <summary>
        /// 判斷包含變數的表達式
        /// </summary>
        /// <param name="func"></param>
        /// <returns></returns>
        private static string VisitMemberExpression(MemberExpression func, DirectionType dirType)
        {
            object value;
            if (dirType == DirectionType.Left || dirType == DirectionType.None)
            {
                value = func.Member.Name;
            }
            else
            {


                switch (func.Type.Name)
                {
                    case "Int32":
                        {
                            var getter = Expression.Lambda<Func<int>>(func).Compile();
                            value = getter();
                        }
                        break;
                    case "String":
                        {
                            var getter = Expression.Lambda<Func<string>>(func).Compile();
                            value = "'" + getter() + "'";
                        }
                        break;
                    case "DateTime":
                        {
                            var getter = Expression.Lambda<Func<DateTime>>(func).Compile();
                            value = "'" + getter().ToString("yyyy-MM-dd HH:mm:ss") + "'";
                        }
                        break;
                    default:
                        {
                            var getter = Expression.Lambda<Func<object>>(func).Compile();
                            value = getter();
                        }
                        break;
                }
            }
            return value.ToString();
        }
View Code
   private static string VisitUnaryExpression(UnaryExpression func)
        {
            var result = "";
            result = GetSqlByExpression(func.Operand);
            return result;
        }
View Code
 1 private static string VisitBinaryExpression(BinaryExpression func)
 2         {
 3             //{(((p.Id == "1") AndAlso (p.OrderNo == "fasdf")) AndAlso (p.CreateTime == DateTime.Now))}
 4             var result = "(";
 5             result += "" + GetSqlByExpression(func.Left, DirectionType.Left) + "";
 6             result += GetNodeType(func.NodeType);
 7             result += "" + GetSqlByExpression(func.Right, DirectionType.Right) + "";
 8             result += ")";
 9             return result;
10         }
View Code
private static string VisitTypeBinaryExpression(TypeBinaryExpression func)
        {
            return "";
        }
View Code
private static string VisitConditionalExpression(ConditionalExpression func)
        {
            return "";
        }
View Code
 1 private static string VisitConstantExpression(ConstantExpression func)
 2         {
 3             var result = "";
 4             if (func.Value.GetType() == typeof(String))
 5             {
 6                 result += "'" + (func.Value.ToString()) + "'";
 7             }
 8             else if (func.Value.GetType() == typeof(Int32))
 9             {
10                 result += "" + (func.Value.ToString()) + "";
11             }
12             else
13             {
14                 throw new Exception("請實現類型");
15             }
16             return result;
17         }
View Code
 1 private static string VisitParameterExpression(ParameterExpression func)
 2         {
 3             var propers = func.Type.GetProperties();
 4             string result = "";
 5 
 6             for (int i = 0; i < propers.Length; i++)
 7             {
 8                 var item = propers[i];
 9                 var itemStr = GetProperInfo(item);
10                 if (!string.IsNullOrEmpty(itemStr))
11                 {
12                     result += itemStr + ",";
13                 }
14             }
15             result = result.TrimEnd(',');
16             return result;
17         }
View Code
 1  /// <summary>
 2         /// 判斷包含函數的表達式
 3         /// </summary>
 4         /// <param name="func"></param>
 5         /// <returns></returns>
 6         private static String VisitMethodCallExpression(MethodCallExpression func)
 7         {
 8             var result = "";
 9             if (func.Method.Name == "Where")
10             {
11                 result += " Where ";
12                 var cente = func.Arguments[1];
13                 result += GetSqlByExpression(cente);
14             }
15             else if (func.Method.Name.Contains("Contains"))
16             {
17                 //獲得調用者的內容元素
18                 var getter = Expression.Lambda<Func<object>>(func.Object).Compile();
19                 var data = getter() as IEnumerable;
20                 //獲得欄位
21                 var caller = func.Arguments[0];
22                 while (caller.NodeType == ExpressionType.Call)
23                 {
24                     caller = (caller as MethodCallExpression).Object;
25                 }
26                 var field = VisitMemberExpression(caller as MemberExpression, DirectionType.Left);
27                 var list = (from object i in data select "'" + i + "'").ToList();
28                 result += field + " IN (" + string.Join(",", list.Cast<string>().ToArray()) + ") ";
29             }
30             else if (func.Method.Name.Contains("Select"))
31             {
32                 result += " Select ";
33                 var cente = func.Arguments[1];
34                 result += GetSqlByExpression(cente);
35             }
36             return result;
37         }
View Code
1  private static string VisitLambdaExpression(LambdaExpression func)
2         {
3             var result = "";
4             result += GetSqlByExpression(func.Body);
5             return result;
6         }
View Code
1  private static string VisitNewExpression(NewExpression func)
2         {
3             var result = "";
4             result += GetSqlByExpression(func.Arguments[0]);
5             return result;
6         }
View Code

  3)根據 ExpressionType 判斷條件類型

 

 1 private static string GetNodeType(ExpressionType expType)
 2         {
 3             var result = "";
 4             if (expType == ExpressionType.AndAlso)
 5             {
 6                 result += " and ";
 7             }
 8             if (expType == ExpressionType.Or)
 9             {
10                 result += " or ";
11             }
12             if (expType == ExpressionType.Equal)
13             {
14                 result += " = ";
15             }
16             if (expType == ExpressionType.NotEqual)
17             {
18                 result += " <> ";
19             }
20             if (expType == ExpressionType.Conditional)
21             {
22                 result += " > ";
23             }
24             if (expType == ExpressionType.LessThan)
25             {
26                 result += " < ";
27             }
28             if (expType == ExpressionType.GreaterThanOrEqual)
29             {
30                 result += " >= ";
31             }
32             if (expType == ExpressionType.LeftShiftAssign)
33             {
34                 result += " <= ";
35             }
36             return result;
37         }
View Code

   4)根據ExpressionType 判斷Expression 子類類型(本列中未用到)

 

 1         public static Expression GetExpression(Expression exp)
 2         {
 3             if (exp == null)
 4                 return exp;
 5             switch (exp.NodeType)
 6             {
 7                 case ExpressionType.Negate:
 8                 case ExpressionType.NegateChecked:
 9                 case ExpressionType.Not:
10                 case ExpressionType.Convert:
11                 case ExpressionType.ConvertChecked:
12                 case ExpressionType.ArrayLength:
13                 case ExpressionType.Quote:
14                 case ExpressionType.TypeAs:
15                     return (UnaryExpression)exp;
16                 case ExpressionType.Add:
17                 case ExpressionType.AddChecked:
18                 case ExpressionType.Subtract:
19                 case ExpressionType.SubtractChecked:
20                 case ExpressionType.Multiply:
21                 case ExpressionType.MultiplyChecked:
22                 case ExpressionType.Divide:
23                 case ExpressionType.Modulo:
24                 case ExpressionType.And:
25                 case ExpressionType.AndAlso:
26                 case ExpressionType.Or:
27                 case ExpressionType.OrElse:
28                 case ExpressionType.LessThan:
29                 case ExpressionType.LessThanOrEqual:
30                 case ExpressionType.GreaterThan:
31                 case ExpressionType.GreaterThanOrEqual:
32                 case ExpressionType.Equal:
33                 case ExpressionType.NotEqual:
34                 case ExpressionType.Coalesce:
35                 case ExpressionType.ArrayIndex:
36                 case ExpressionType.RightShift:
37                 case ExpressionType.LeftShift:
38                 case ExpressionType.ExclusiveOr:
39                     return (BinaryExpression)exp;
40                 case ExpressionType.TypeIs:
41                     return (TypeBinaryExpression)exp;
42                 case ExpressionType.Conditional:
43                     return (ConditionalExpression)exp;
44                 case ExpressionType.Constant:
45                     return (ConstantExpression)exp;
46                 case ExpressionType.Parameter:
47                     return (ParameterExpression)exp;
48                 case ExpressionType.MemberAccess:
49                     return (MemberExpression)exp;
50                 case ExpressionType.Call:
51                     return (MethodCallExpression)exp;
52                 case ExpressionType.Lambda:
53                     return (LambdaExpression)exp;
54                 case ExpressionType.New:
55                     return (NewExpression)exp;
56                 case ExpressionType.NewArrayInit:
57                 case ExpressionType.NewArrayBounds:
58                     return (NewArrayExpression)exp;
59                 case ExpressionType.Invoke:
60                     return (InvocationExpression)exp;
61                 case ExpressionType.MemberInit:
62                     return (MemberInitExpression)exp;
63                 case ExpressionType.ListInit:
64                     return (ListInitExpression)exp;
65                 default:
66                     throw new Exception(string.Format("Unhandled expression type: '{0}'", exp.NodeType));
67             }
View Code

2.構建上下文類型IECContext

  

 1  public class IECContext: IDisposable
 2     {
 3         public static string ConnectionString { get; set; }
 4         public static string ConnectionKey { get; set; }
 5 
 6         public IECContext(string key)
 7         {
 8             ConnectionKey = key;
 9             ConnectionString = ConfigurationManager.ConnectionStrings[key].ConnectionString;
10         }
11 
12         public void Dispose()
13         {
14             this.Dispose();
15         }
16     }
View Code

3.構建DBSet 對象,需要實現IQueryable<T> 介面

 1 public class DBSet<T> : IQueryable<T>, IQueryable, IEnumerable<T>, IEnumerable, IOrderedQueryable<T>, IOrderedQueryable
 2     {
 3 
 4         QueryProvider provider;
 5         Expression expression;
 6         public DBSet(QueryProvider provider)
 7         {
 8 
 9             if (provider == null)
10             {
11                 throw new ArgumentNullException("QueryProvider不能為空");
12             }
13             this.provider = provider;
14             this.expression = Expression.Constant(this);
15         }
16 
17         public DBSet(QueryProvider provider, Expression expression)
18         {
19             if (provider == null)
20             {
21 
22                 throw new ArgumentNullException("QueryProvider不能為空");
23             }
24 
25             if (expression == null)
26             {
27                 throw new ArgumentNullException("Expression不能為空	   

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

-Advertisement-
Play Games
更多相關文章
  • 做了好幾天,對象比較多,弄的都是亂的,最後還是一個個試出來的。 Bitmap Graphics FromImage Pen Rectangle DrawRectangle 真的混亂,看了好幾天,才明白參數之間的關係。 下載 pan.baidu.com/s/1c2CMRhY 思路:form1 就是界面 ...
  • 問題3:使用webform,每次提交後臺界面都要刷新,能不能讓我們與後臺 交互的時候像ajax一樣,界面不用刷新,同時還能返回參數並且繼續在前臺執行?? 相信很多人和我一樣,這也是很多人開發放棄webform最重要的原因吧!!這也是很多人覺得webform不好的原因吧!!!其實mvc提交form表單 ...
  • 如果你沒有看我第二天寫的內容的,我想你是看不懂的!!!! 好了,廢話不多說,怎麼才能讓我們的代碼變得牛逼起來呢?怎麼封裝我們的代碼呢?我們不可能 每個頁面都需要那樣寫吧,那我們來一步一步來封裝 我們的代碼,變得更牛逼,維護性更高!!!!! 首先我們來分析,我昨天寫的代碼: 第一步:在界面寫入2個隱藏 ...
  • 問題2: 每次與後臺打交道 都需要寫一些自己都看不太懂的事件,而且傳參數很麻煩,這就是.net 封裝的事件,如何解決呢? 首先不要以為寫webfrom事件,都需要通過 伺服器控制項來綁定後臺的事件,其實說白了綁定的事件其實都是form表單提交,而且還都是id為form1的表單提交。 如果你不知道這些, ...
  • 修飾符 應用於 說明 public 所有類型或成員 任何代碼都可以訪問 protected 類型和內嵌類型的所有成員 只有派生的類型可以訪問 internal 所有類型或成員 只能在包含它的程式集中訪問 private 類型和內嵌類型的所有成員 只能在它所屬的類型中訪問 protected inte... ...
  • 1 public class Program1 2 { 3 #region 結構 4 //結構是值類型,存儲在棧上 5 //1:結構中的成員變數不能有初始值 6 //2:結構中不能聲明無參數構造函數 7 struct Example 8 { 9 //public int Width = 1;//錯誤 ...
  • 1 class Program 2 { 3 //數組是引用類型 4 //如果把數組或類等其他引用類型傳遞給方法,對應的方法就會使用該引用類型改編數組中值, 5 //而新值會反射到原始數組上 6 static void SomeFunction(int[] ints, int i) 7 { 8 int ...
  • 1、前言 surging受到不少.net同學的青睞,也提了不少問題,提的最多的是什麼時候集成API 網關,在這裡回答大家最近已經開始著手研發,應該在1,2個月內會有個初版API網關,其它像Token身份驗證,限流降級等功能完成時間會往後推 最近也更新了surging新的版本 更新內容: 1. Cac ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...