一.什麼是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不能為空