深入医生orm之insert细节

这是第一次看一个组件的细节和内幕,好在医生的代码注释很多,堪称典范

首先是看看生成的实体类

因为医生宣称自己的orm没有使用反射,对此深感好奇,就看看是怎么插入数据和映射的

生成的实体类代码如下

using System;
using PWMIS.Common;
using PWMIS.DataMap.Entity;

namespace SuperMarket 
{
  [Serializable()]
  public partial class userinfo : EntityBase
  {
    public userinfo()
    {
            TableName = "userinfo";
            EntityMap=EntityMapType.Table;
            //IdentityName = "标识字段名";
    IdentityName="id";

            //PrimaryKeys.Add("主键字段名");
    PrimaryKeys.Add("id");

            
    }


      protected override void SetFieldNames()
      {
           PropertyNames = new string[] { "id","username","userpassword","userbrief","userimg" };
      }



      /// <summary>
      /// 
      /// </summary>
      public System.Int32 id
      {
          get{return getProperty<System.Int32>("id");}
          set{setProperty("id",value );}
      }

      /// <summary>
      /// 
      /// </summary>
      public System.String username
      {
          get{return getProperty<System.String>("username");}
          set{setProperty("username",value ,50);}
      }

      /// <summary>
      /// 
      /// </summary>
      public System.String userpassword
      {
          get{return getProperty<System.String>("userpassword");}
          set{setProperty("userpassword",value ,50);}
      }

      /// <summary>
      /// 
      /// </summary>
      public System.String userbrief
      {
          get{return getProperty<System.String>("userbrief");}
          set{setProperty("userbrief",value ,1073741823);}
      }

      /// <summary>
      /// 
      /// </summary>
      public System.String userimg
      {
          get{return getProperty<System.String>("userimg");}
          set{setProperty("userimg",value ,50);}
      }


  }
}
 
[Serializable()]
首先这个实体类是可以序列化的,为以后的缓存做好了准备,不过这个效率不太高,实现可序列化接口就更好了
userinfo : EntityBase
实体类继承字同一个实体对象,基类应该是对象转换相关的

TableName = "userinfo";

这里指定了实体对应的表的名称,应该是生成sql预计时候用的,也为以后的分库分表横向拆分做好了准备
EntityMap=EntityMapType.Table;

protected override void SetFieldNames()
     {
          PropertyNames = new string[] { "id","username","userpassword","userbrief","userimg" };
     }

这里保存了一个表所有的字段的名称

 

     /// <summary>
     ///
     /// </summary>
     public System.Int32 id
     {
         get{return getProperty<System.Int32>("id");}
         set{setProperty("id",value );}
     }

这里是一个字段的属性,对这个属性进行读写时,并不是直接读写,而是调用基类的方法,进行存储

实体类就这么多

再调式看看

调试上次插入的代码

            SuperMarket.userinfo objuserinfo = new SuperMarket.userinfo();
            EntityQuery<SuperMarket.userinfo> query = new EntityQuery<SuperMarket.userinfo>(objuserinfo,true);
            objuserinfo.username = "互联网fans";
            objuserinfo.userpassword = "1234567";
            objuserinfo.userimg = "http://tp2.sinaimg.cn/1271114553/180/5614484664/1";
            objuserinfo.userbrief = @"博客园菜鸟级博主,七脸阁主题APP开发者,专注于WebApp的开发和研究,
提倡通过命题作文寻找创新的灵感和创意的点子。
新浪应用搜索最新作品:表情帝。";
            //query.Save();
           // Response.Write(objuserinfo.id);
            int id= query.Insert(objuserinfo);
            Response.Write(id);

先跟中一下赋值,医生的orm赋值有很多猫腻在里面,得看看

objuserinfo.username = "互联网fans";

跟进去后

微博桌面截图_20121125114439

进入赋值环节

微博桌面截图_20121125114637

赋值环节先根据表名称和字段名称生成了个key,然后存储了字段的长度,并比较了值的长度是否溢出,防止插入数据库时出错

检查完成后开始赋值

3

这里不清楚是所有的属性默认都是null,还是因为我的表设计的默认值允许为null,下次在检验一下

赋值时对PropertyNames属性列表进行遍历,找到赋值的属性就赋值,并在changedlist[i] 标记这个值已经变化了,为插入数据库时只插入赋值的字段做好了准备

另外这里还注册了一个事件,虽然没弄明白注册这个时间是干嘛的有什么用,有没有性能风险,例如,web并发时候注册事件有没有影响,主要是不知道这个是干嘛的

赋值到这里就完了,医生之所以没用使用映射,就是记录了表一共有那些字段,给那些字段赋值了,然后就可以插入了

插入是个方法,医生没有放到实体类里面去而是新建了查询类

EntityQuery<SuperMarket.userinfo> query = new EntityQuery<SuperMarket.userinfo>(objuserinfo,true);

public EntityQuery(T entity,bool newEntity)
{
     isNew = newEntity;
     init(entity);
}

private void init(T entity)
{
    entity.PropertyGetting += new EventHandler<PropertyGettingEventArgs>(entity_PropertyGetting);
    entity.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(entity_PropertyChanged);
    currEntity = entity;
}

创建这个查询时也注册了不少事件,并指定了这个查询是那个实体类的查询,不清楚web应用程序频繁的注册事件对性能影响几何,哎

跟入inser方法

4

在insert 方法中先判断了一下实体中字段的数量,然后指定了默认的数据库连接字符串

在接下来

 private static int InsertInner(T entity, List<string> objFields, CommonDB DB)
        {
            if (objFields == null || objFields.Count == 0)
                return 0;

            IDataParameter[] paras = new IDataParameter[objFields.Count];
            //CommonDB DB = MyDB.GetDBHelper();


            string sql = "INSERT INTO [" + entity.TableName+"]";
            string fields = "";
            string values = "";
            int index = 0;

            foreach (string field in objFields)
            {
                if (entity.IdentityName != field)
                {
                    fields += ",[" + field+"]";
                    string paraName = DB.GetParameterChar + "P" + index.ToString();
                    values += "," + paraName;
                    paras[index] = DB.GetParameter(paraName, entity.PropertyList(field));
                    //为字符串类型的参数指定长度 edit at 2012.4.23
                    if( paras[index].Value!=null && paras[index].Value.GetType()==typeof(string))
                    {
                        ((IDbDataParameter)paras[index]).Size = entity.GetStringFieldSize(field);
                    }
                    
                    index++;
                }
            }
            sql = sql + "(" + fields.TrimStart(',') + ") VALUES (" + values.TrimStart(',') + ")";

            int count = 0;

            if (entity.IdentityName != "")
            {
                //有自增字段
                object id = entity.PropertyList(entity.IdentityName);
                count = DB.ExecuteInsertQuery(sql, CommandType.Text, paras, ref id);
                entity.setProperty(entity.IdentityName, Convert.ToInt32(id));
            }
            else
            {
                count = DB.ExecuteNonQuery(sql, CommandType.Text, paras);
            }
            if (count > 0)
                entity.ResetChanges();

            return count;

        }


 

if (objFields == null || objFields.Count == 0)
    return 0;

IDataParameter[] paras = new IDataParameter[objFields.Count];

判断有没有字段,然后根据字段的数量创建参数列表

string sql = "INSERT INTO [" + entity.TableName+"]";
           string fields = "";
           string values = "";
           int index = 0;

           foreach (string field in objFields)
           {
               if (entity.IdentityName != field)
               {
                   fields += ",[" + field+"]";
                   string paraName = DB.GetParameterChar + "P" + index.ToString();
                   values += "," + paraName;
                   paras[index] = DB.GetParameter(paraName, entity.PropertyList(field));
                   //为字符串类型的参数指定长度 edit at 2012.4.23
                   if( paras[index].Value!=null && paras[index].Value.GetType()==typeof(string))
                   {
                       ((IDbDataParameter)paras[index]).Size = entity.GetStringFieldSize(field);
                   }
                   index++;
               }
           }
           sql = sql + "(" + fields.TrimStart(',') + ") VALUES (" + values.TrimStart(',') + ")";

遍历字段 拼写sql并给sql参数赋值

if (entity.IdentityName != "")
{
    //有自增字段
    object id = entity.PropertyList(entity.IdentityName);
    count = DB.ExecuteInsertQuery(sql, CommandType.Text, paras, ref id);
    entity.setProperty(entity.IdentityName, Convert.ToInt32(id));
}
else
{
    count = DB.ExecuteNonQuery(sql, CommandType.Text, paras);
}

在执行 sql语句时候,看有没有自增id,如果有自增id,执行时返回自增的id,没有的话就返回影响的行数

感觉这里IdentityName 不太准确,自增id,主键,等等应该详细描述

插入的就这么多

剩下的就是调用sql帮助类了

另外发现,orm默认没有实现读写分离,这点很不好。。。。。。。。。。。。。。。。。。

                    

 
原文地址:https://www.cnblogs.com/qqloving/p/2797021.html