• 和我一起学CSLA.NET创建业务对象2


        上一节我们已经创建了我们业务对象的属性和简单的验证规则,这一节我们主要来实现数据门户 ,首先先大概介绍一下CSLA数据访问相关的概念:
        Csla框架的数据门户通过通道适配器模式和消息路由模式合并起来,提供了对服务器上所有数据访问操作的一个简单明了的入口点。实际上,数据门户完全隐藏了服务器的参与,这就使得应用程序能在不改变代码的情况下,在两层和三层物理部署之间自由切换。数据门户有以下特点:
        
    实现了移动对象
         隐藏了网络传输(通道适配器)
         暴露了对服务器的唯一入口点(消息路由)
         暴露了服务器端资源(数据库引擎、分布式事务等)
         统一了上下文(在客户端和服务器之间传递上下文)
        数据门户强制了你的对象和数据访问层或者是ORM交互的标准和结构. 这个标准化保留了灵活性,使你能够自由的使用几乎任何你选择的数据访问技术,包括但不仅限于:      
        纯ADO.NET(Connection,data readers等)
        DataSet和TableAdapter对象
        LINQ to SQL
        LINQ to XML
        ADO.NET Entity Framework
        Nhibernate  和其它第三方ORM工具
        简单的文件I/O
        远程XML或者是JSON服务

       CSLA的数据访问门户的标准就是每个业务对象提供DataPortal_XYZ方法,负责进行创建、提取、添加、更新和删除,然后在业务对象工厂方法中调用数据门户的对应方法就是转换成调用提供的DataPortal_XYZ方法:
       fig02
    一个完整的可编辑的对象一般要实现如下几个数据门户的方法(这部分代码可以放到业务对象类中、分离在单独的类中、分离在单独的程序集中、使用对象工厂方法):
       DataPortal_Create()      对象被创建时将会被调用,在这里可以设置默认值.
       DataPortal_Fetch()        被数据门户调用来装载对象的数据
       DataPortal_Insert()       处理新对象的持久化保存
       DataPortal_Update()      处理脏对象的持久化更新
       DataPortal_DeleteSelf()
       DataPortal_Delete()        CSLA提供了两种删除对象的方法:立即删除 延迟删除. 延迟删除就是说在对象被装载到内存中的时候,IsDeleted属性被设置成true,当调用对象的Save()时,这时候会在内部调用DataPortal_DeleteSelf方法。立即删除是指显示调用DataPortal.Delete方法并且传递标志要删除对象的查询条件, 数据门户DataPortal在内部会调用此对象的DataPortal_Delete方法.
       我们一个一个的来实现以上几个方法,首先是DataPortal_Create:

    隐藏行号 复制代码 Product.DataPortal_Create
    1. [RunLocal()]
    2. protected override void DataPortal_Create()
    3. {
    4.     using (BypassPropertyChecks)
    5.     {
    6.         ProductID = Guid.NewGuid().ToString();
    7.         ValidationRules.CheckRules();
    8.     }
    9. }

        1. [RunLocal()]特性标明此方法在本地运行,而不是在应用服务器上运行,这在分布式服务器部署上能够缩短处理时间.
        2. 由于此方法没有数据库相关的操作,只是简单的属性值初始化,没有必要调用服务器的相关资源,所以才会使用[RunLocal()]标明在本地运行,假如你需要调用数据库资源来进行初始化的话,就不需要打RunLocal标签了.
        3. Product业务对象只需要给主键生成一下Guid字符串,然后我们会手动调用ValidationRules.CheckRules验证一下此业务对象是否符合校验规则.
        4. BypassPropertyChecks是新增的特性,因为在上一节我们介绍过,如果直接通过Name = "TestName"其实是调用的GetProperty,这样在内部会进行一些检查,如果需要在业务对象内部给属性赋值的话,为了性能或者其它原因,想绕过安全或者其它检查,一般需要这样写
            LoadProperty<string>(NameProperty, "TestName")
    而现在可以直接使用BypassPropertyChecks, 是不是这样方便多了.
         
        接下来添加DataPortal_Fetch:

    隐藏行号 复制代码 Product.DataPortal_Fetch
    1. private void DataPortal_Fetch(SingleCriteria<Product, string> criteria)
    2. {
    3.     using (var ctx =
    4.       ContextManager<CSLADemo.DalLinq.CSLADemoDataContext>.
    5.       GetManager(CSLADemo.DalLinq.Database.CSLADemo))
    6.     {
    7.         var data = (from p in ctx.DataContext.Products
    8.                     where p.ProductID == criteria.Value
    9.                     select p).Single();
    10.         using (BypassPropertyChecks)
    11.         {
    12.             ProductID = data.ProductID;
    13.             ItemName = data.ItemName;
    14.             ItemNo = data.ItemNo;
    15.         }
    16.     }
    17. }

         1.参数为SingeCriteria,其实是表明能够代表当前业务对象的标识,在这里业务对象是Product,主键是string类型,如果在这里你的主键为多个(一般不推荐)的话,你需要实现自己的Criteria。
         2.这里包含根据ProductID获取Product对象的linq实现,在这里就不详细介绍了,其中CSLADemo.DalLinq.Database中的CSLADemo变量存储的是数据库的名字

        我们再来添加DataPortal_Insert: 

    隐藏行号 复制代码 Product.DataPortal_Insert
    1. [Transactional(TransactionalTypes.TransactionScope)]
      
    2.        protected override void DataPortal_Insert()
      
    3.        {
      
    4.            using (var ctx =
      
    5.              ContextManager<CSLADemo.DalLinq.CSLADemoDataContext>.
      
    6.              GetManager(CSLADemo.DalLinq.Database.CSLADemo))
      
    7.            {
      
    8.                using (BypassPropertyChecks)
      
    9.                {
      
    10.                    var data = new CSLADemo.DalLinq.Product();
      
    11. 
      
    12.                    data.ProductID = ReadProperty(ProductIDProperty);
      
    13.                    data.ItemNo = ReadProperty(ItemNoProperty);
      
    14.                    data.ItemName = ReadProperty(ItemNameProperty);
      
    15. 
      
    16.                    ctx.DataContext.Products.InsertOnSubmit(data);
      
    17.                    ctx.DataContext.SubmitChanges();
      
    18.                }
      
    19.                FieldManager.UpdateChildren(this);
      
    20.            }
      
    21.        }
      

         1.[Transactional()]特性用来保证此方法事务性.
         2.当调用业务对象的Save方法时,如果此对象的IsNew=True,数据门户会自动调用此方法.
         3.FieldManager.UpdateChildren(this)是指在更新完后,更新所有的子对象,这个在后面介绍
     
       同样的,我们添加另外三个数据门户方法:

    隐藏行号 复制代码
    1. [Transactional(TransactionalTypes.TransactionScope)]
      
    2.         protected override void DataPortal_Update()
      
    3.         {
      
    4.             using (var ctx =
      
    5.                 ContextManager<CSLADemo.DalLinq.CSLADemoDataContext>.
      
    6.                 GetManager(CSLADemo.DalLinq.Database.CSLADemo))
      
    7.             {
      
    8.                 using (BypassPropertyChecks)
      
    9.                 {
      
    10.                     var data = new CSLADemo.DalLinq.Product()
      
    11.                     {
      
    12.                         ProductID = ReadProperty(ProductIDProperty)
      
    13.                     };
      
    14.                     if (IsSelfDirty)
      
    15.                     {
      
    16.                         data.ItemNo = ReadProperty(ItemNoProperty);
      
    17.                         data.ItemName = ReadProperty(ItemNameProperty);
      
    18.                         ctx.DataContext.Products.Attach(data, true);
      
    19.                     }
      
    20.                 }
      
    21.                 FieldManager.UpdateChildren(this);
      
    22. 
      
    23.                 ctx.DataContext.SubmitChanges();
      
    24.             }
      
    25.         }
      
    26. 
      
    27.         [Transactional(TransactionalTypes.TransactionScope)]
      
    28.         protected override void DataPortal_DeleteSelf()
      
    29.         {
      
    30.             DataPortal_Delete(
      
    31.               new SingleCriteria<Product, string>(ProductID));
      
    32.         }
      
    33. 
      
    34.         [Transactional(TransactionalTypes.TransactionScope)]
      
    35.         private void DataPortal_Delete(SingleCriteria<Product, string> criteria)
      
    36.         {
      
    37.             using (var ctx =
      
    38.               ContextManager<CSLADemo.DalLinq.CSLADemoDataContext>.
      
    39.               GetManager(CSLADemo.DalLinq.Database.CSLADemo))
      
    40.             {
      
    41.                 var data = ctx.DataContext.Products
      
    42.                      .Single(r => r.ProductID == criteria.Value);
      
    43. 
      
    44.                 ctx.DataContext.Products.DeleteOnSubmit(data);
      
    45.                 ctx.DataContext.SubmitChanges();
      
    46.             }
      
    47.         }
      

         1.DataPortal_Delete为private,因为它不并不会被自动调用。在这里,提供了延迟加载功能,所以在DataPortal_DeleteSelf里调用DataPortal_Delete.

     代码下载

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

  • 相关阅读:
    MySQL优化
    数据库之事务
    浮动与定位的区别
    CSS-画三角
    CSS(中)篇
    CSS(前)篇
    html篇
    定位真机运行能用但是打包成apk就不能用的解决方法
    定位与权限
    activity与fragment之间的传递数据
  • 原文地址:https://www.cnblogs.com/lonely7345/p/1665171.html
Copyright © 2020-2023  润新知