WAWACRM

基于.NET的开源CRM项目
做一件事,一定要坚持。意志不坚定的,参加也没意义。

导航

 

关于CMP架构改进的几个想法,欢迎大家交流
  第一个考虑CMP和DAAB3.1的合并,我想凡是对业务实体的操作都用CMP来进行持久化,凡是主要业务外的持久操作都用DAAB3.1来实现,比如说对查看订单,更新购物车,删除员工之类的操作都用CMP来实现,因为CMP内置监测跟踪,异常处理,串行化实体等功能,这些可以帮助业务逻辑代码的调试和开发。比如说从数据库里选择一列来填充一个下拉列表(非功能性需求),获取某个表里的时间戳列等这些行为都不是应用系统的主要行为,而是辅助行为,如果都对他们进行配置元数据,建立存储过程等无疑会增加工作量而没有其它的好处,所以用helper类执行比较好,能获得很好的灵活性,而且DAAB3.1如果执行标准的ANSI SQL的话可以做到多种数据库透明操作,在修改了底层数据库后业务代码几乎也不用修改。
  第二个想法就是原来的CMP架构在进行Select操作后如果返回多条数据的话使用的是标准的DataSet来保存数据的,而返回单条数据是直接用类似CustomerEntity这样的实体类来保存数据的,而现在有一种趋势就是使用带类型的DataSet来保存多条实体数据,比如CustomerSet,EmployeeSet等,这样就可以用oDs.Customers[0].Name来代替oDs.Tables["Customers"].Rows[0]["Name"].ToString,这样使用数据比较OO,所以我想改进一下CMP核心类,让它获取数据集的时候传入一个类型参数,以获得强类型的数据集,比如以下这段代码返回的是catSet对象里的一个DataTable。

SqlPersistenceContainer spc = new SqlPersistenceContainer( CMPConfigurationHandler.ContainerMaps["Categories"] );
CategorySet catSet 
= new CategorySet();
catSet.CategoryId 
= categoryId;
spc.Select( catSet );
catSet.FinalizeData();   
return catSet.ResultSet.Tables[0];


上面这段返回的DataTable可以直接去绑定页面数据控件,而我想我们应该也可以直接返回catSet,然后用catSet[0].ID来访问第一个购物车的ID,这点修改虽然不是很必要,但是可以是业务逻辑更明晰,要实现上述功能可能需要修改PersistableObjectSet基类

相关文章:使用强类型数据集进行有效编码
http://www.microsoft.com/china/MSDN/library/data/dataAccess/DataPoints.mspx

  第三个想法就是对事务的支持,要想让CMP支持容器管理事务,在实例容器的时候必须得传递一个数据库链接对象和一个事务对象,我想大概用下面的办法来实现CMT

public void TextTransaction() 
        
{
            SqlConnection conn 
= null;
            SqlTransaction tran 
= null;
            
try
            
{
                conn 
= new SqlConnection("server=(local);database=northwind;uid=sa;pwd=sa");
                conn.Open();
                tran 
= conn.BeginTransaction();
                CMPConfigurationHandler.initContainerMappingSet(
@"E:\vs2005project\TestConcurrencyAndTransaction\Config\Customer.xml");
                StdPersistenceContainer  spc 
= new SqlPersistenceContainer(CMPConfigurationHandler.ContainerMaps["Customer"],conn,tran);
                Console.WriteLine(
"Hello Wrold!");
                tran.Commit();
            }

            
catch (Exception ex)
            
{
                tran.Rollback();
                Console.WriteLine(ex.GetType().ToString() 
+ ":" + ex.Message);
                Console.WriteLine(ex.StackTrace);
            }

            
finally
            
{
                conn.Close();
            }

  然后架构代码需要修改的就是根据不同的构造函数来加载不同重载版本的BuildCommandFromMapping方法,如果传递进来一个事务和链接对象,就在构建Command的时候就不重新建立链接对象了,就直接用传递进来的连接和事务构建Command,CMP内部也就不用管理连接的断开等工作了,事务的提交,回滚还有连接的建立和断开都在CMP外部的业务逻辑里管理。当然了上面的例子不是很好,我用了SqlConnection和SqlTransaction,实际上应该用接口引用,而不是实现类来引用,这点我还没有想好。
  第四个想法就是对乐观并发的支持,我是这样想的,如果想让一个实体支持并发处理,让除了继承PersistableObject类外,再实现一个IConcurrentEntity接口

 public interface IConcurrentEntity
 
{
  System.Data.SqlTypes.SqlBinary GetTimestamp();
  
void RefreshTimestamp();
  
bool HasChanged();
 }


  我来解释这个接口,GetTimestamp()用来返回当前业务实体的时间戳,RefreshTimestamp()是用数据库里当前实体的时间戳来更新当前实体的时间戳,这个呢,需要用到实体的主键来检索对应在数据库里的那条记录,并提取时间戳字段的值,这个主要是用在你对实体进行了持久操作后还继续使用实体,这时候需要更新实体的时间戳属性。HasChanged()是用在你将要持久化实体的时候用的,如果当前实体的时间戳和数据库里实体对应记录的时间戳不同的话就返回false,因为这时候可能在你加载数据后哪条数据可能被人修改过了,你可以在执行持久实体操作的时候调用实体的这个方法,如果返回否的话,触发一个事件,或者引发一个异常,都行。因为实体类我们可能是用辅助的代码生成器来生成的,而RefreshTimestamp()的具体实现,我想使用DAAB3.1来实现,毕竟这是很简单的操作,只需要确定实体对应表的主键字段,时间戳字段,实体对应的表,以及实体实例的主键属性值这几项就可以获取数据库的时间戳,我想把这个方法抽象出来应该不难。
  最后一点是关于自动化操作的,就是用实体主动支持标准的CRUD操作,以方便使用,毕竟大多数业务对象都需要添加,删除,修改,检索等操作的,如果实体能靠继承某个接口来自动实现自身的CRUD操作的话,会减少我们相当多的工作,这点,我想也要给持久性实体引入一个新的基类,让这个基类来帮助实体进行标准的CRUD操作,我想这里也不是很难,好多ORM架构都实现了标准的CRUD操作,而且有的还搞出了一套定制生成标准CRUD操作的方法,比如SPL。这一点主要是为了提高开发效率,我想具体实现可能也要靠DAAB3.1来做,其实这一点非常不好实现的,要考虑的地方也多,比如在执行标准CRUD操作的时候的异常处理,跟踪,实体的串行化等都要和CMP架构本身统一起来,我们要保证在调试阶段能trace这些操作的执行情况,到底哪些数据插入了数据库,数据库的哪些字段改变了,我们应该在不随时查看数据库的情况下用页面跟踪来查看这些,良好的调试和跟踪功能也是加快开发的一个重要因素。
  其实持久层和实体层要考虑的东西还有好多方面,比如如何让容器自动监测实体的变化,并自动持久化,持久层和业务层之间的交互等等,为了不让我们的架构过于复杂难用,暂时考虑先做以上的改进。
  我们的项目的持久层框架我就是这么考虑的,业务层框架和表示层框架另开贴讨论。欢迎各位有志之士参与我们的讨论,支持我们的项目。