你的位置:首页 > ASP.net教程

[ASP.net教程]一个简单得不能再简单的“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

 

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

 

源码下载:

 源码下载