EMStudio系列教程6--EMLib框架之Orm
EMLib真正的强大之处就是它具备的ORM功能,EMLib允许开发者用完全面向对象的方式操作数据库。并且无需考虑数据层中的任何细节,也无需关心当前使用的是何种数据库,为开发带来极大的便利。

一.EMLib开发环境的配置
这部分内容请参考EMStudio系列教程5--EMLib框架之Eql中相关内容。配置方法是完全一样的。下面给出一个简单的例子看一下,配置完以后如何使用EMLib完成实体的查询操作,代码如下所示:
  
                                        // 模型文件的路径,该文件由Entity Model Studio在生成源代码时同时生成
                                        string pathModel = "...";
                                        // 许可证文件路径,在完成试用版注册或者正式版许可证注册后许可证管理器
                                        // 会自动生成该文件
                                        string pathLic = "...";
                                        // CustomModelSqlCS.ED是Entity Model Studio自动生成的类,其中的方法
                                        // CreateContext也是自动生成的。用于完成EMContext对象的生成。
                                        EmContext context = CustomModelSqlCS.ED.CreateContext(pathModel, pathLic);
                                        // 构造Sql数据库的连接对象
                                        EMSqlConnection conn = new EMSqlConnection(context);
                                        // 构造Sql数据库的命令连接对象
                                        EMSqlCommand comm = new EMSqlCommand(conn);
                                        // 使用Eql接口完成查询语句对象的构造
                                        EqlSelect stmt = Eql.Select(CustomModelSqlCS.ED.E7000).
	                                        From(CustomModelSqlCS.ED.E7000).
	                                        Where(CustomModelSqlCS.ED.E7000.ID > 10);
                                        // 连接数据库。这里无需指明连接字符串,该字符串是在模型文件中配置的。
                                        conn.Open();
                                        // 使用Eql语句对象完成查询实体的ORM功能。参数EntityAffectType.Data用
                                        // 于控制级联的深度。
                                        ReadOnlyCollection result = comm.QueryEntity(stmt, EntityAffectType.Data);
                                        // 关闭连接
                                        conn.Cloes();
                                        
二.EMLib的ORM接口
EMLib的ORM接口由EMLib.Entity命名空间中的各个类提供。其中命名空间的结构,类的种类和微软.Net框架是一致的。命名空间的比较如下图所示:

各个类的比较如下图所示:

读者可以自行确认一下,各个类中的方法也是一致,只是EMLib框架增加了支持ORM功能的方法。为了节省篇幅,这里就不再列出比较了。EMLib框架提供的ORM接口所具有的这样的特点,使得已经了解.Net框架接口的开发者可以无需学习就能掌握EMLib框架的使用。

三.EMContext类
EMContext是静态模型的上下文类,这个类包含了静态模型的所有信息。这些信息在构造该类的对象时通过传入模型文件来获得。所有ORM功能的实现都需要这个类的支持。可以说这是最基础,最重要的一个类。这里简单的介绍几个重要的可配置的属性。

1.ConnectionString
这个属性表示当前使用的连接字符串。一般来说这个连接字符串存在于模型文件中,是在静态模型设计时就已经指定了。为了给开发带来更多的灵活性,EMLib框架允许开发者动态的修改这个属性,以便达到定制的要求。

2.UpdateBatchSize
数据库的更新(Update)和插入(Insert),对于EMLib框架来说都是通过Save方法完成的。在框架内部EMLib自动识别需要执行的是更新还是插入操作。那么对于更新操作,出于性能的考虑EMLib框架使用的是批量更新的方式。这个属性就是设置一次批量更新多少条数据。开发者可以根据自己实际面对的情况,动态修改这个数据,从而得到最佳的性能。

3.EnableEMTransaction
这个属性用于通知EMLib框架在执行ORM操作时是否使用内存事务。EMLib框架的内存事务和数据库中的事务是保持同步的,如果提交那么一起提交,如果回滚那么一起回滚。从而使得内存中的实体及其关系的结构和数据库中的数据完全一致。完整意义上的体现了对象关系映射的意义。这个属性设置为true那么EMLib框架就使用内存事务,否则不使用。需要注意的是,内存事务在某些情况下会导致性能问题。相对不使用内存事务的情况,会执行更多的数据库操作。所以开发者需要根据具体情况,决定是否使用该功能。

4.EnableEntityPool
这个属性表示是否在执行ORM操作时使用实体缓存。实体缓存的存在不但可以提高性能,而且还可以保证激活得到的实体对象是全局唯一的。从而保证面向对象的机制得到有效的体现。一般情况我们建议该属性设置为true,允许EMLib使用实体缓存。使用实体缓存是可以提高性能的。

四.基本操作的实现
这里所说的基本操作是指:增删改查这四个操作。下面的代码演示新增一个实体:
  
                                        Company company = new Company();
                                        company.Address = "My Address";
                                        company.CompanyName = "WideUnion Tech";
                                        comm.Save(company);
                                        
示例中调用Save方法后,在框架内部最终执行的是插入操作,因为新实体没有被保存过。一旦Save操作执行成功,company对象的State属性会改为Active,EntityId属性改为该实体在数据表中的主键值。如果以后再次修改该实体对象的属性值,然后调用Save方法,那么框架内部最终执行的是更新操作。

删除操作的例子:
  
                                        Company company = new Company();
                                        company.Address = "My Address";
                                        company.CompanyName = "WideUnion Tech";
                                        comm.Save(company);
                                        comm.Remove(company);
                                        
先保存实体,然后再删除,删除后实体对象的State和EntityId属性值为改变,以表示该实体已经被删除。注意以下例子使用Eql方式也可以达到删除相同数据的目的:
  
                                        Company company = new Company();
                                        company.Address = "My Address";
                                        company.CompanyName = "WideUnion Tech";
                                        comm.Save(company);
                                        EqlDelete stmt = Eql.Delete(MyContext.Company).
	                                        From(MyContext.Company).
	                                        Where(MyContext.Company.ID == company.EntityId);
                                        comm.Remove(stmt);
                                        
当如上例那样使用Eql方式删除数据时,如果这时开启了数据库事务同时又使用内存事务,那么删除后company对象的State属性和EntityId属性会改变,以表示该实体被删除了。当事务回滚的时候,company对象的State属性和EntityId属性会恢复到删除操作执行前的值,这就是内存事务的效果。如果没有使用内存事务,那么company对象的State属性和EntityId属性在删除后和事务回滚后都不会变化。

查询实体的例子: 实体查询操作只能通过Eql方式完成,如下所示:
  
                                        EqlSelect stmt = Eql.Select(MyContext.Company).
	                                        From(MyContext.Company).
	                                        Where(MyContext.Company.ID > 10);
                                        ReadOnlyCollection company = comm.QueryEntity(stmt);
                                        
五.关系操作
在EMLib框架中关系操作有三种:建立,终止和转移。建立关系是指在两个实体之间建立关系,对应数据库来说就是修改指定的外键值为某一个实体的主键。终止关系是指修改指定的外键值使其不指向任何实体的主键。关系的转移操作是EMLib提供的一个特色,它的含义是一个实体A原来和实体B之间有关系,通过关系转移操作可以将该关系转移A和C之间建立关系,同时终止A和B之间的关系。所有这三种操作都是支持两种方式:实体方式和Eql方式。尤其是Eql方式可以給开发者带来很大的便利,如果在配合内存事务的话,就会更加方便。

关系建立的例子:
  
                                        // 实体方式
                                        comm.SetupRelation(company.HasEmployee, employee);
                                        // Eql方式
                                        EqlSelect stmt = Eql.Select(MyContext.Employee).
	                                        From(MyContext.Employee).
	                                        Where(MyContext.Employee.ID == employee.EntityId);
                                        comm.SetupRelation(company.HasEmployee, stmt);
                                        
关系终止的例子:
  
                                        // 实体方式
                                        comm.BreakRelation(company.HasEmployee, employee);
                                        // Eql方式
                                        EqlSelect stmt = Eql.Select(MyContext.Employee).
	                                        From(MyContext.Employee).
	                                        Where(MyContext.Employee.ID == employee.EntityId);
                                        comm.BreakRelation(company.HasEmployee, stmt);
                                        
关系转移的例子:
  
                                        // 实体方式
                                        comm.TransitRelation(company1.HasEmployee, company2.HasEmployee, employee);
                                        // Eql方式
                                        EqlSelect stmt = Eql.Select(MyContext.Employee).
	                                        From(MyContext.Employee).
	                                        Where(MyContext.Employee.ID == employee.EntityId);
                                        comm.TransitRelation(company1.HasEmployee, company2.HasEmployee, stmt);
                                        
例子中演示的是,将employee对象的HasEmployee关系从company2转移到company1对象。等价于先执行company2和employee之间的终止关系操作,再执行company1和employee之间的关系建立操作。

六.级联操作
EMLib中级联操作只对查询,更新,删除三种操作有效,并且支持实体和Eql两种方式。级联操作的深度控制是通过参数EntityAffectType来完成的。参数EntityAffectType具体使用和含义在帮助文档的相关部分有非常详细的说明,这里就不再重复了。

七.懒加载
和其它ORM框架不同的是,EMLib的懒加载只对查询操作中的级联部分而言的。懒加载的有效是开发者在查询实体时没有启用级联操作。如果启用级联操作懒加载将无效,所有查询实体都会被实际构造而不是在访问时再查询得到。如下例是懒加载有效的例子:
 
                                        EqlSelect stmt = Eql.Select(MyContext.Company).
	                                        From(MyContext.Company).
	                                        Where(MyContext.Company.ID > 10);
                                        // 使用参数EntityAffectType.Data表示只激活实体本身的数据,不执行任何级联操作。
                                        ReadOnlyCollection company = comm.QueryEntity(stmt, EntityAffectType.Data);
                                        // 这时访问HasEmployee属性就会执行懒加载
                                        company[0].HasEmployee.Count.ToString();
                                        
下面的例子中懒加载是不会起作用的:
 
                                        EqlSelect stmt = Eql.Select(MyContext.Company).
	                                        From(MyContext.Company).
	                                        Where(MyContext.Company.ID > 10);
                                        // 使用参数EntityAffectType.Full表示执行所有的级联操作。那么QueryEntity
                                        // 方法执行完,所有实体就都被激活了,所以懒加载失效。
                                        ReadOnlyCollection company = comm.QueryEntity(stmt, EntityAffectType.Full);
                                        // 这时访问HasEmployee属性不会执行懒加载
                                        company[0].HasEmployee.Count.ToString();
                                        
八.角色和元素
对于角色和元素操作只有两种:建立和终止。使用方法和关系的建立于终止一致,只是调用的方法不同。从本质上说,角色和元素也是一种关系。

九.刷新操作
刷新操作是强制从数据库中读取数据更新实体各个属性的值。通过调用Refresh方法完成。

十.对.Net框架扩展的方法
这个扩展是允许开发者使用Eql语句对象执行原来.Net框架支持的操作,由于都是非常易于理解的所以就简单介绍一下。

1.QueryDataReader
该方法是对ExecuteReader方法的扩展,使用例子如下:
 
                                        EqlSelect stmt = Eql.Select(MyContext.Company).
	                                        From(MyContext.Company).
	                                        Where(MyContext.Company.ID > 10);
                                        DbDataReader dr = comm.QueryDataReader(stmt);
                                        
2. QueryDataSet
该方法提供一个更为方便的途径得到一个DataSet数据集,例子如下:
 
                                        EqlSelect stmt = Eql.Select(MyContext.Company).
	                                        From(MyContext.Company).
	                                        Where(MyContext.Company.ID > 10);
                                        DataSet ds = comm.QueryDataSet(stmt);
                                        
通过这种扩展大幅度扩展了Eql语句对象能够使用的场合,允许开发者在不使用ORM功能的前提下也可以得到Eql提供的便利。在面对常规方式操作数据还是ORM操作数据这两种 选择,开发者可以非常灵活的选择最佳方式完成开发任务。

EMLib框架的主要内容大致就是这些,当然还有很多使用的细节没有全部介绍,限于篇幅就写到这里了。更多内容开发者可以在实践中逐步体会。如果遇到疑问,或者需要技术支持可以访问我们网站:www.WideUnion.com。提出您的问题,或者直接发邮件到我们的邮箱:Contact@WideUnion.com或者UMLerChina@hotmail.com,我们的开发团队会尽快给予答复。
Copyright 2014--2020 广联科技版权所有