这是第一次看一个组件的细节和内幕,好在医生的代码注释很多,堪称典范
首先是看看生成的实体类
因为医生宣称自己的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";
跟进去后
进入赋值环节
赋值环节先根据表名称和字段名称生成了个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, 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默认没有实现读写分离,这点很不好。。。。。。。。。。。。。。。。。。