本文適合初學者,老鳥請點贊即走,謝謝。 文字功底有限,表述不恰當的地方,請各位多多包涵。 一,核心 現在ORM已經很多了,功能也齊全了,大家說我這是乾無聊的事,造的連車輪子都還不算,反正我就當學習。 還有就是,下麵這個不算正在的ORM,離真正在ORM差的很遠的。 主要思想 二,實例測試 1,基礎數據 ...
本文適合初學者,老鳥請點贊即走,謝謝。
文字功底有限,表述不恰當的地方,請各位多多包涵。
一,核心
現在ORM已經很多了,功能也齊全了,大家說我這是乾無聊的事,造的連車輪子都還不算,反正我就當學習。
還有就是,下麵這個不算正在的ORM,離真正在ORM差的很遠的。
主要思想
二,實例測試
1,基礎數據準備
1.1 資料庫表結構(sqlite資料庫)
1.2 實體
public class Msg { public string Id { get; set; } public string Content { get; set; } public string Name { get; set; } public DateTime CreateTime { get; set; } }
2,開始插入數據
2.1 創建了一個控制台程式做測試
string connStr = string.Format("Data Source={0};", System.AppDomain.CurrentDomain.BaseDirectory + "App_Data\\db.db"); WangSql.ISqlExe sqlexe = new WangSql.SqlExe(WangSql.DbType.SQLLITE, connStr); string sql = "insert into Msg(Id,Content,Name,CreateTime) values(#Id#,#Content#,#Name#,#CreateTime#)"; Msg model = new Msg() { Id = Guid.NewGuid().ToString("N"), Content = "這裡是內容", Name = "姓名", CreateTime = DateTime.Now }; sqlexe.NonQuery(sql, model);
查看下數據呢,
至此,測試成功,再來測試下呢。
2.2 開8個線程,每個線程迴圈插入100條數據試試看。
測試結果:好尷尬sqlite多線程容易鎖庫,以後操作這個庫,還是隊列吧,樓主本著不放棄不拋棄的精神,再來了一次。
這次沒被鎖,資料庫數據呢。
數據也沒少,OK,測試完成。
三,源碼講解(準確的是代碼講解)
3.1 生成SQL
大家有沒有發現,我在執行時傳入sql的格式
insert into Msg(Id,Content,Name,CreateTime) values(#Id#,#Content#,#Name#,#CreateTime#)//有沒有很熟悉呢,沒錯,就是借鑒(山寨)的ibatis的,哈哈
就是這個樣子的,
表:Msg(Id,Content,Name,CreateTime)
DbDataParameter:values(#Id#,#Content#,#Name#,#CreateTime#)
DbDataParameter,這裡支持值類型,string,object,object[],以及Hashtable和用戶自定義類。
下麵就是生成SQL語句的代碼、
public string SqlInit(string sql, out List<string> paraName) { string sqlTag = sql; List<string> sqlParaName = new List<string>(); Regex regex = new Regex("(#(.[^#]+?)#)"); var ms = regex.Matches(sql); foreach (Match item in ms) { var p1 = item.Groups[1]; var p2 = item.Groups[2]; sqlTag = sqlTag.Replace(p1.Value, prefix + p2.Value); if (!sqlParaName.Contains(p2.Value)) sqlParaName.Add(p2.Value); } paraName = sqlParaName; return sqlTag; }
這個就會生成sql,並且還會把Parameter的key以集合的方式拋出去。
3.2 實體轉成DbDataParameter
當插入數據,參數傳入的是個用戶自定義類的話,需要做一次轉換。先將實體轉成Hashtable,然後再根據3.1生成sql拋出來的Parameter的key來生成Parameter集合。
public static Hashtable ModelToHashtable(object model) { Hashtable ht = new Hashtable(); BindingFlags flag = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; PropertyInfo[] propertys = model.GetType().GetProperties(flag); foreach (PropertyInfo pi in propertys) { string name = pi.Name; if (!pi.CanRead) continue; object value = pi.GetValue(model, null); ht.Add(name, value); } return ht; }
3.3 完整NonQuery執行代碼
public int NonQuery(string sql, object para) { if (IsModel(para))//Model入參 { Hashtable ht = DataMapHelper.ModelToHashtable(para); List<string> paraName = new List<string>(); string sqlTag = SqlInit(sql, out paraName); IDbDataParameter[] sqlParas = DBFactory.CreateDbDataParameters(type, paraName.Count); for (int i = 0; i < paraName.Count; i++) { string key = paraName[i]; object value = ht[key]; sqlParas[i] = DBFactory.CreateDbDataParameter(type, prefix + key, value); } var result = helper.ExecuteNonQuery(sqlTag, sqlParas); return result; } else if (para.GetType() == typeof(Hashtable))//Hashtanle入參 { Hashtable ht = (Hashtable)para; List<string> paraName = new List<string>(); string sqlTag = SqlInit(sql, out paraName); IDbDataParameter[] sqlParas = DBFactory.CreateDbDataParameters(type, paraName.Count); for (int i = 0; i < paraName.Count; i++) { string key = paraName[i]; object value = ht[key]; sqlParas[i] = DBFactory.CreateDbDataParameter(type, prefix + key, value); } var result = helper.ExecuteNonQuery(sqlTag, sqlParas); return result; } else if (para.GetType() == typeof(object[])) { List<string> paraName = new List<string>(); string sqlTag = SqlInit(sql, out paraName); object[] ht = (object[])para; IDbDataParameter[] sqlParas = DBFactory.CreateDbDataParameters(type, paraName.Count); for (int i = 0; i < paraName.Count; i++) { string key = paraName[i]; object value = ht[i]; sqlParas[i] = DBFactory.CreateDbDataParameter(type, prefix + key, value); } var result = helper.ExecuteNonQuery(sqlTag, sqlParas); return result; } else//一個參數入參 { List<string> paraName = new List<string>(); string sqlTag = SqlInit(sql, out paraName); IDbDataParameter[] sqlParas = DBFactory.CreateDbDataParameters(type, paraName.Count); for (int i = 0; i < paraName.Count; i++) { string key = paraName[i]; object value = para; sqlParas[i] = DBFactory.CreateDbDataParameter(type, prefix + key, value); } var result = helper.ExecuteNonQuery(sqlTag, sqlParas); return result; } }
3.4 查詢語句
如果是查詢的話,執行完SQL返回一個DataTable,操作DataTable也太麻煩了吧,所以利用反射做了個實體轉換器。
DataTable轉實體Model,DataRow轉實體Model,DataTable轉泛型T,DataRow轉泛型T (之前的文章)
public static T DataRowToModel<T>(DataRow row) { T model; Type type = typeof(T); ModelType modelType = GetModelType(type); switch (modelType) { case ModelType.Struct://值類型 { model = default(T); if (row[0] != null) model = (T)row[0]; } break; case ModelType.Enum://值類型 { model = default(T); if (row[0] != null) { Type fiType = row[0].GetType(); if (fiType == typeof(int)) { model = (T)row[0]; } else if (fiType == typeof(string)) { var value = Enum.Parse(typeof(T), row[0].ToString()); if (value != null) model = (T)value; } } } break; case ModelType.String://引用類型 c#對string也當做值類型處理 { model = default(T); if (row[0] != null) model = (T)row[0]; } break; case ModelType.Object://引用類型 直接返回第一行第一列的值 { model = default(T); if (row[0] != null) model = (T)row[0]; } break; case ModelType.Else://引用類型 { model = System.Activator.CreateInstance<T>();//引用類型 必須對泛型實例化 #region MyRegion //獲取model中的屬性 BindingFlags flag = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; PropertyInfo[] modelPropertyInfos = type.GetProperties(flag); //遍歷model每一個屬性並賦值DataRow對應的列 foreach (PropertyInfo pi in modelPropertyInfos) { if (!pi.CanWrite) continue; //獲取屬性名稱 string tempName = GetFieldName(pi); String name = string.IsNullOrEmpty(tempName) ? pi.Name : tempName; if (row.Table.Columns.Contains(name) && row[name] != null) { ModelType piType = GetModelType(pi.PropertyType); switch (piType) { case ModelType.Struct: { var value = Convert.ChangeType(row[name], pi.PropertyType); pi.SetValue(model, value, null); } break; case ModelType.Enum: { Type fiType = row[name].GetType(); if (fiType == typeof(int)) { pi.SetValue(model, row[name], null); } else if (fiType == typeof(string)) { var value = Enum.Parse(typeof(T), row[name].ToString()); if (value != null) pi.SetValue(model, (T)value, null); } } break; case ModelType.String: { var value = Convert.ChangeType(row[name], pi.PropertyType); pi.SetValue(model, value, null); } break; case ModelType.Object: { pi.SetValue(model, row[name], null); } break; case ModelType.Else: //throw new Exception("不支持該類型轉換"); break; default: throw new Exception("未知類型"); } } } #endregion } break; default: model = default(T); break; } return model; }
好了,差不多了吧,還有些多謝沒講,可以看我另外兩篇博客。
DataTable轉實體Model,DataRow轉實體Model,DataTable轉泛型T,DataRow轉泛型T
最後項目截圖吧,稍後源碼附上。
源碼下載: