• 一个简单得不能再简单的“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

    最后项目截图吧,稍后源码附上。

    源码下载:

     源码下载

  • 相关阅读:
    CA 证书和数字证书
    PHP获取不了内网IP?
    站点速度检测工具
    Mac地址
    交互机和路由器区别
    关于实体店收银系统和cookie实现登录状态
    Python3 的序列
    Python3 字符串格式化
    Python3 的元组
    Python3 的列表
  • 原文地址:https://www.cnblogs.com/deeround/p/5670891.html
Copyright © 2020-2023  润新知