和我一起学CSLA.NET----创建业务对象3

      到现在为止, 我们已经为业务对象创建了属性,验证规则,数据门户.除了属性我们会直接使用,验证规则和数据门户我们不会手动直接调用的,而最通常调用的是我们的业务对象的工厂方法,在这一节,我们就为Product对象添加了些通用的工厂业务方法,并且介绍一下工厂方法调用的内部细节,以及业务对象的相关细节。
      首先我们必须要了解一下业务对象的Save方法,这个方法是CSLA约定的基本业务对象BusinessBase<T>内置实现的,源代码如下:

隐藏行号 复制代码 BusinessBase.Save
  1. public virtual T Save()
  2. {
  3.   T result;
  4.   if (this.IsChild)
  5.     throw new NotSupportedException(Resources.NoSaveChildException);
  6.   if (EditLevel > 0)
  7.     throw new Validation.ValidationException(Resources.NoSaveEditingException);
  8.   if (!IsValid && !IsDeleted)
  9.     throw new Validation.ValidationException(Resources.NoSaveInvalidException);
  10.   if (IsBusy)
  11.     throw new Validation.ValidationException(Resources.BusyObjectsMayNotBeSaved);
  12.   if (IsDirty)
  13.     result = (T)DataPortal.Update(this);
  14.   else
  15. result = (T)this;
  16.   OnSaved(result, null, null);
  17.   return result;
  18. }

     前几个判断和异常我们暂且不管,我们看到当属性IsDirty为True时,会调用数据门户的Update(以下是此方法代码片断),而在Update方法内部,CSLA其实是会根据当前业务对象不同的状态进行不同的处理,如果业务对象是新增对象(IsNew=True),则通过反射调用业务对象的DataPortal_Insert方法,如果为已经标记删除的对象(IsDeleted=True),则调用对象的DataPortal_DeleteSelf方法,否则调用业务对象的更新方法DataPortal_Update, 以下就是DataPortal.Update方法的内部代码片断:

隐藏行号 复制代码
  1.    string methodName;
  2.           if (obj is CommandBase)
  3.           {
  4.             //注意这里的方法名都是写死的,这和基类BusinessBase里定义的一致,所以数据门户的方法名是固定的
  5. methodName = "DataPortal_Execute";
  6.             operation = DataPortalOperations.Execute;
  7.             //反射之前会进行权限判断
  8. if (!Csla.Security.AuthorizationRules.CanEditObject(objectType))
  9.               throw new System.Security.SecurityException(string.Format(Resources.UserNotAuthorizedException,
  10.                 "execute",
  11.                 objectType.Name));
  12.           }
  13.           else
  14. {
  15.             var bbase = obj as Core.BusinessBase;
  16.             if (bbase != null)
  17.             {
  18.               if (bbase.IsDeleted)
  19.               {
  20.                 methodName = "DataPortal_DeleteSelf";
  21.                 if (!Csla.Security.AuthorizationRules.CanDeleteObject(objectType))
  22.                   throw new System.Security.SecurityException(string.Format(Resources.UserNotAuthorizedException,
  23.                     "delete",
  24.                     objectType.Name));
  25.               }
  26.               else
  27.                 if (bbase.IsNew)
  28.                 {
  29.                   methodName = "DataPortal_Insert";
  30.                   if (!Csla.Security.AuthorizationRules.CanCreateObject(objectType))
  31.                     throw new System.Security.SecurityException(string.Format(Resources.UserNotAuthorizedException,
  32.                       "create",
  33.                       objectType.Name));
  34.                 }
  35.                 else
  36. {
  37.                   methodName = "DataPortal_Update";
  38.                   if (!Csla.Security.AuthorizationRules.CanEditObject(objectType))
  39.                     throw new System.Security.SecurityException(string.Format(Resources.UserNotAuthorizedException,
  40.                       "save",
  41.                       objectType.Name));
  42.                 }
  43.             }
  44.             else
  45. {
  46.               methodName = "DataPortal_Update";
  47.               if (!Csla.Security.AuthorizationRules.CanEditObject(objectType))
  48.                 throw new System.Security.SecurityException(string.Format(Resources.UserNotAuthorizedException,
  49.                   "save",
  50.                   objectType.Name));
  51.             }
  52.           }
  53.           method = Server.DataPortalMethodCache.GetMethodInfo(obj.GetType(), methodName);
  54.         }
  55.        //...下面是调用这个方法了
  56. 
    

     这里列出来了比较多的代码,其实这也是一种学习CSLA框架的一个手段,他的源代码并不是很复杂,结合着实例去学习他的源代码对我们能够很好的使用这个开源框架很有帮助. 很多问题只有你知道了它的具体原理,你才能够真正的去充分利用它的价值,也就会避免来滥用它.不要迷恋它,也不能低估它.
      以上之所以介绍业务对象的Save方法,是想说明,在这个方法内部已经提供了业务对象的更新,延迟删除,保存,所以说我们工厂方法没有必要提供这三个方法了,这样我们暂时不考虑业务直接相关的方法,还差创建对象,直接删除,获取对象三个方法了,我们依次添加这三个方法: 

隐藏行号 复制代码 Factory Methods
  1. #region  Factory Methods
    
  2. 
    
  3. public static Product NewProduct()
    
  4. {
    
  5.     return DataPortal.Create<Product>();
    
  6. }
    
  7. public static Product GetProduct(string id)
    
  8. {
    
  9.     return DataPortal.Fetch<Product>(new SingleCriteria<Product, string>(id));
    
  10. }
    
  11. public static void DeleteProduct(string id)
    
  12. {
    
  13.     DataPortal.Delete(new SingleCriteria<Product, string>(id));
    
  14. }
    
  15. private Product()
    
  16. { }
    
  17. 
    
  18. #endregion
    

      1.首先是创建对象的方法NewProduct(),可能有些人可能会不太明白这个方法为什么存在,CSLA约定所有业务对象实现非public构造函数,防止用户new一个业务对象,强制UI开发人员使用工厂方法来使用业务对象,可以看到我们最下面的默认构造方法都是私有的,你不能够在外面直接通过new来创建我们的业务对象.
      2.业务方法调用的数据门户相应的实现,其实就和业务对象的数据门户的方法一一对应,这个我们在上一节有介绍,比如这里调用的DataProtal.Create其实就是调用的我们的业务对象内部实现的DataPortal_Create,只不在调用时自动封装了上下文,进行了通道处理,进行了安全验证.
      3.业务方法都是static的静态方法.

      到现在为止,我们已经完成了一个基本的业务对象,包括它的属性,验证,数据门户,业务方法,现在可以对我们的业务对象进行一下测试了,很简单,我们使用Vs.Net带的单元测试,新建一个测试项目, 然后注意新增一个配置文件来配置我们的数据库连接, 再添加我们针对Product业务对象的单元测试类即可了,我们先简单的测试一下创建和保存方法:

隐藏行号 复制代码 Test
  1. 
    
  2. /// <summary>
    
  3. ///NewProduct 的测试
    
  4. ///</summary>
    
  5. [TestMethod()]
    
  6. public void NewProductTest()
    
  7. {
    
  8.     Product actual;
    
  9.     actual = Product.NewProduct();
    
  10.     actual.ItemNo = "000001";
    
  11.     actual.ItemName = "山寨手机Nexus one";
    
  12.     Assert.IsNotNull(actual.ProductID);
    
  13. }
    
  14. 
    
  15. [TestMethod()]
    
  16. public void SaveProductTest()
    
  17. {
    
  18.     Product actual;
    
  19.     actual = Product.NewProduct();
    
  20.     actual.ItemNo = "000001";
    
  21.     actual.ItemName = "山寨手机Nexus one";
    
  22.     actual.Save();
    
  23. 
    
  24.     Product expected = Product.GetProduct(actual.ProductID);
    
  25.     Assert.IsNotNull(expected);
    
  26.     Assert.AreEqual(actual.ItemNo, expected.ItemNo);
    
  27. }
    

     右击运行单元测试,我们可以直接查看测试结果,直接测试我们的业务对象的相关特性,或者是调试过程来查看一些内部流程.

     接下来,还是来提示一些业务对象的一些使用上的细节:
     1.当使用工厂方法NewXXX创建一个对象后,在DataPortal_Create里对这个对象的默认值进行初始化,对象的属性IsNew=True,然后需要调用业务对象内置的Save方法,才保存这个对象
     2.如果你调用业务对象内置的Delete()方法,其实是设置这个业务对象的IsDeleted=True,IsDirty=True,然后需要调用业务对象内置的Save方法,来完成这个对象的持久化,这就是我们提到过的延迟删除(也可以通过查看我们上面提到的Save方法的内部处理看出来).
     3.如果你调用业务对象内置的Save方法,对象不是是以上说的两种情况,而且进行过更改,属于脏对象(IsDirty=True),那么会执行这个对象的更新操作,也就是会调用数据门户提供的DataPortal_Update方法.
   
  不过我们的业务对象还比较简单,到现在并没有考虑到主子关系,也没有处理安全验证,更没有应用CSLA的移动对象,这些概念我们会在下面一一介绍.

 代码下载

作者:孤独侠客似水流年
出处:http://lonely7345.cnblogs.com/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

posted @ 2010-02-08 16:46 孤独侠客 阅读(...) 评论(...) 编辑 收藏