这是第一次看一个组件的细节和内幕,好在医生的代码注释很多,堪称典范
首先是看看生成的实体类
因为医生宣称自己的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" }; } ////// /// public System.Int32 id { get{ return getProperty("id");} set{setProperty("id",value );} } /// /// /// public System.String username { get{ return getProperty("username");} set{setProperty("username",value ,50);} } /// /// /// public System.String userpassword { get{ return getProperty("userpassword");} set{setProperty("userpassword",value ,50);} } /// /// /// public System.String userbrief { get{ return getProperty("userbrief");} set{setProperty("userbrief",value ,1073741823);} } /// /// /// public System.String userimg { get{ return getProperty("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(); EntityQueryquery = new EntityQuery (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";
跟进去后
进入赋值环节
赋值环节先根据表名称和字段名称生成了个key,然后存储了字段的长度,并比较了值的长度是否溢出,防止插入数据库时出错
检查完成后开始赋值
这里不清楚是所有的属性默认都是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方法
在insert 方法中先判断了一下实体中字段的数量,然后指定了默认的数据库连接字符串
在接下来
private static int InsertInner(T entity, ListobjFields, 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默认没有实现读写分离,这点很不好。。。。。。。。。。。。。。。。。。