前言
最近园子整天为了不是技术的东西在讨论,我就调节一下气氛。介绍一下我开发的ORM框架。还有基本的实现原理。
条条大路通罗马,源码等就不公开了,还是那句,思想才是最重要的。
代码例子
实体类的设计
只要继承了OrmBase,就实现了orm操作,不需要写任何的配置文件
{
string userName;
OrmRole temprole;
List<string> addresses;
List<OrmRole> roleList;
[OrmPrimaryKey]
public string UserName
{
get { return userName; }
set { userName = value; }
}
public OrmRole Temprole
{
get { return temprole; }
set { temprole = value; }
}
public List<string> Addresses
{
get { return addresses; }
set { addresses = value; }
}
public List<OrmRole> RoleList
{
get { return roleList; }
set { roleList = value; }
}
}
public class OrmRole : OrmBase
{
string name;
public string Name
{
get { return name; }
set { name = value; }
}
}
目前支持了所有的值类型,还有string类型,自定义的class,List类型,Array类型;至于Dictionary其他的不是很通用我就不支持了。
部署过程
只要操作Commit,就可以把ORM映射到数据库,至于怎么映射的,这个不是用户考虑的,因此我的ORM操作起来非常的顺手。没有任何多余的代码、多余的配置。
普通调用过程
{
OrmUser user = new OrmUser();
user.UserName = "helloworld" + i;
OrmRole role = new OrmRole();
role.Name = "role" + i;
}
过程中,每一步包括创建、赋值都已经直接操作了数据库,所以我的orm和普通的OO代码没有任何区别。
但是这样调用性能是很低的,每次赋值都会插入数据库,因此,我提供了缓存功能。
缓存操作
for (int i = 0; i < 100; i++)
{
OrmUser user = buffer.Create<OrmUser>();
user.UserName = "helloworld" + i;
OrmRole role = buffer.Create<OrmRole>();
role.Name = "role" + i;
}
buffer.Commit();
如果使用了缓存,那么在Commit之前,所有操作都在内存,这样极大的提高了速度!
当然,在commit里面使用了一定的优化算法,比如合并同类数据等等,减少操作数据库的次数。
ORM的关键——查询问题
ORM是否成功,关键就是查询的实现,我自己编写了一套面向对象的查询语法,非常的简单(不要和Hibernate的HQL对比哦)
先展示一个简单的查询例子
IOrmRightQuery query = OrmManager.Instance.RightQuery;
query.Obj = user;
query.Position = "USER.ROLELIST";
List<OrmRole> list = query.Select<OrmRole>();
这个是向右查询。意思是:我知道了User的对象,想查询他的RoleList的所有值。
使用起来顾名思义,所以我的查询语法是非常简单的,就是【对象】的【属性】的【属性】,
例如User有个属性ROleList,那么查询就是User.RoleList。
复杂的向右查询
query.Position = "user.roleList.Permission.ResList.Value = :VALUE";
query.Paras.Add("VALUE", resName);
return query.Select<string>().Count > 0;
这个查询是我的权限框架里面经常用到的,就是查询:
当前用户的 角色列表里面的 授权项目里面的 资源名 是否包含输入的资源resName
User RoleList Permission ResList.Value
绝对的顾名思义,估计什么人都很快上手的。
向左查询实例
query.Condition = "PROJECTNAME = :PROJECTNAME AND STATUS = :STATUS";
query.Paras.Add("PROJECTNAME", projectName);
query.Paras.Add("STATUS", WorkflowStatus.Running);
return query.Select<WfProjectInstance>();
这个是个向左查询的例子,是我的工作流框架里面常用的查询。
1. 我要查询一个对象叫做WfProjectInstance
2. 这个对象的projectName = projectName、状态=WorkflowStatus.Running
混合查询
IOrmAdvanceQuery<PageRole> advance = OrmManager.Instance.GetAdvanceQuery<PageRole>();
IToLeftQuery left = advance.CreateToLeftQuery();
left.Condition = "PageRole.RoleName= :ROLENAME";
left.Paras.Add("ROLENAME", "MERCHANT_LEVEL_03");
IToRightQuery right = advance.CreateToRightQuery();
right.Obj = user;
right.Position = "USER.PAGEROLELIST";
List<PageRole> list = advance.Select(right, left);
最后一个是我最精华的查询:混合查询;结合了向右查询和向左查询。
具体解释我就不说了,由于混合查询的sql性能比较低,我用的还是比较少的。其实设计合理,一般是不用混合查询的。
设计思路
现在简单介绍一下我的ORM的一些技术思路。
1. AOP
用了.net提供的AOP思路,本质就是一个基于Message模型的调用。因此对实体类所有操作,会被AOP拦截,然后判断用户需要操作的对象、返回类型;然后转化为SQL获取数据。
2. Reflect
用了反射,这个也是必然的,除了对值类型(Valuetype)反射,还有自定义的class的反射,获取元数据,然后组成sql
3. ORM的理论
比如 User {List<Role> list;}
这个类,会被映射为三张表
A:TB_USER表
B:TB_USER_LIST的链接表
C:TB_ROLE 表
其实掌握了基本的ORM理论,知道对象如何映射为表之后,就能够实现大部分功能了。这个还多亏了Oracle的ORm资料,写的非常详细,让我少走了很多弯路。
4. 一些自定义的表名、主键值生成
要使用方便,那么就要把很多灵活的操作变得不灵活,比如表名的命名、主键的生成,这些我都会让ORM自己完成,不需要程序员手动设置。
是牺牲了一些代价,但是只要你使用了我的orm,换回来的是非常良好的操作和维护。
5. OO的设计模式和理论
良好的设计模式事半功倍,在我的ORM框架里面
1)所有自定义对象会被映射为一个ObjProxy对象,这个称为对象代理;因此对自定义类的操作,会变成ObjProxy的操作
2)结合一些设计模式,能够使缓存操作、事务操作变得非常简单,只需要做几个切换,用一些接口的方法之类的。
总而言之,良好的设计模式是必须的。
后续
本人自不量力,在此发出一份挑战书,希望有牛人觉得他的作品比我的更优秀,拿出来晒晒,好让我惭愧惭愧。
其实我更多的是希望能够获得新的思想,而不是激起矛盾。
那么,在心平气和的前提下,我敬候挑战者的到来!