一個簡單得不能再簡單的“ORM”了


本文適合初學者,老鳥請點贊即走,謝謝。

文字功底有限,表述不恰當的地方,請各位多多包涵。

一,核心

      現在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;
        }

 

 

 

 

好了,差不多了吧,還有些多謝沒講,可以看我另外兩篇博客。

萬能的SqlHelper,麻麻再也不用擔心用什么數據庫了

DataTable轉實體Model,DataRow轉實體Model,DataTable轉泛型T,DataRow轉泛型T

 

最后項目截圖吧,稍后源碼附上。

 

源碼下載:

 源碼下載

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM