用户操作
[即时聊天] [发私信] [加为好友]
job_2006ID:job_2006
1082次访问,排名2万外好友3人,关注者6
job_2006的文章
原创 0 篇
翻译 0 篇
转载 26 篇
评论 1 篇
最近评论
xfblue:代码挺好用,用你的登录代码解决了登录问题,发现网上的文章都是说了一堆废话,让人摸不到头脑,原来实现如此简单...
文章分类
收藏
    相册
    博客园
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    转载 微型项目实践(7):数据访问的定义收藏

    新一篇: C# ,webBrowser,登录,数据填充,模拟点击链接,运行JS函数 | 旧一篇: 微型项目实践(6):Business层代码分析——实体类的生成策略

    上一篇中我们分析了实体类,这一篇我们来看看数据访问是怎么设计的。

    system_design

    从系统结构图中可以看出,到目前为止我们没有任何关于数据库访问的实现部分,而Business则仅仅是给出了IDatabase和IEntityDataAccess这两个用于定义数据访问要实现什么功能的接口。我们认为数据访问如何实现是系统的细节,而领域模型(业务逻辑)是抽象,抽象的领域模型定义、但不关心、更不依赖数据访问和数据库的设计与实现。相反,作为实现的细节,数据层根据业务逻辑的需要实现,随业务逻辑的变更而变更,这也符合DIP(接口倒置原则)。上面的系统结构图,添加数据访问后,应该是这个样子:

    system_design

    不仅仅是数据访问依赖于Business,UI——无论是Windows的还是Web的,也依赖于Business。在开发Web层的时候,我们还会重申这个问题。

    这样的设计有很多好处:

    1. 业务逻辑直接来源于需求,由它决定系统的其它部分符合从已知到未知、从抽象到具体、从定义到实现的思维方向。需求变,则业务逻辑变;业务逻辑变,则系统皆变,这是必然的。反之数据存储及访问的方式的变更、UI显示方法的优化不会、也不应该影响业务逻辑。
    2. 数据层和表现层的可替换性。既然数据存储和UI设计的实现不会影响Business,那么这两个模块自然是可以替换的,所以当我们换用不同的数据源(Sql2000、MySql甚至XML时)或者使用不同的数据访问方法时(Linq或者自己手写SQL),只需要从新实现Business定义的接口即可。UI层类似。
    3. 可测试的业务逻辑。既然业务逻辑不依赖于数据层和表现层,那么业务逻辑层的测试就更不会依赖具体的数据库或者表现层实现方式。通常的做法就是用接口定义数据访问层需要实现的操作,测试的时候就可以用伪实现模拟不同状态的数据上下文,实现自动化测试代码。这点对于测试数据源发生错误或者数据非法的情况极为有用。

    了解了各层次的依赖关系后,我们来看Business是如何定义数据访问的:

    Business

    数据访问使用两个接口定义,IEntityDataAccess和IDatabase,前者描述了对于一个实体的数据访问应该实现的功能,后者描述了整个数据库应该具有的功能。IEntityAccess的定义如下:

       1:  using System;
       2:  using System.Collections.Generic;
       3:  using System.Linq;
       4:  using System.Text;
       5:   
       6:  namespace DongBlog.Business
       7:  {
       8:      /// <summary>
       9:      /// 实体数据访问接口
      10:      /// </summary>
      11:      /// <typeparam name="T">实体类型</typeparam>
      12:      public interface IEntityDataAccess<T> : IQueryable<T>
      13:      {
      14:          /// <summary>
      15:          /// 添加实体
      16:          /// </summary>
      17:          /// <param name="entity">实体</param>
      18:          void Add(T entity);
      19:   
      20:          /// <summary>
      21:          /// 删除实体
      22:          /// </summary>
      23:          /// <param name="entity">要删除的实体</param>
      24:          void Remove(T entity);
      25:          /// <summary>
      26:          /// 删除实体
      27:          /// </summary>
      28:          /// <typeparam name="TSubEntity">实体类型或派生类</typeparam>
      29:          /// <param name="entities">要删除的实体列表</param>
      30:          void RemoveAll<TSubEntity>(IEnumerable<TSubEntity> entities) where TSubEntity : T;
      31:   
      32:          /// <summary>
      33:          /// 取得对应的数据库
      34:          /// </summary>
      35:          IDatabase Database { get; }
      36:      }
      37:  }

    接口的定义看似很简单,但是要注意到,该接口继承了IQueryable接口,所以实际上是个复杂的接口,而实现了IQueryable接口,就可使用大部分Linq查询方法。IDatabase的定义更为简单:

       1:  using System;
       2:  using System.Collections.Generic;
       3:  using System.Linq;
       4:  using System.Text;
       5:   
       6:  using DongBlog.Business.Blogs;
       7:   
       8:  namespace DongBlog.Business
       9:  {
      10:      /// <summary>
      11:      /// 数据库接口
      12:      /// </summary>
      13:      public interface IDatabase
      14:      {
      15:          /// <summary>
      16:          /// 取得某一个实体的数据访问
      17:          /// </summary>
      18:          /// <typeparam name="T">实体类型</typeparam>
      19:          /// <returns>该实体的数据访问</returns>
      20:          IEntityDataAccess<T> GetDataAccess<T>() where T : class;
      21:   
      22:          /// <summary>
      23:          /// 提交数据库变更
      24:          /// </summary>
      25:          void Submit();
      26:   
      27:      }
      28:  }

    只有“取得各个实体的数据访问”和“提交数据库变更”两个方法。为了方便使用,我们修改一下数据库接口的定义,如下:

       1:  using System;
       2:  using System.Collections.Generic;
       3:  using System.Linq;
       4:  using System.Text;
       5:   
       6:  using DongBlog.Business.Blogs;
       7:   
       8:  namespace DongBlog.Business
       9:  {
      10:      /// <summary>
      11:      /// 数据库接口
      12:      /// </summary>
      13:      public interface IDatabase
      14:      {
      15:          /// <summary>
      16:          /// 取得某一个实体的数据访问
      17:          /// </summary>
      18:          /// <typeparam name="T">实体类型</typeparam>
      19:          /// <returns>该实体的数据访问</returns>
      20:          IEntityDataAccess<T> GetDataAccess<T>() where T : class;
      21:   
      22:          /// <summary>
      23:          /// 提交数据库变更
      24:          /// </summary>
      25:          void Submit();
      26:   
      27:          #region Blogs
      28:   
      29:          /// <summary>
      30:          /// 取得日志数据访问
      31:          /// </summary>
      32:          IEntityDataAccess<Blog> Blogs { get; }
      33:          /// <summary>
      34:          /// 取得日志分类数据访问
      35:          /// </summary>
      36:          IEntityDataAccess<Blog> BlogClasss { get; }
      37:   
      38:          #endregion
      39:   
      40:      }
      41:  }

    加入了Blog和BlogClass的特有类型的数据访问,这样做的目的纯粹是为了方便。有了这两个属性,我们就可以实现前面所说的“database.Blogs.GetByID(1);”这样的调用。

    下一篇文章我们将看到数据访问层究竟是如何实现的。

     

    代码下载

    发表于 @ 2008年05月10日 13:20:22|评论(loading...)|编辑

    新一篇: C# ,webBrowser,登录,数据填充,模拟点击链接,运行JS函数 | 旧一篇: 微型项目实践(6):Business层代码分析——实体类的生成策略

    评论:没有评论。

    发表评论  


    当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
    Csdn Blog version 3.1a
    Copyright © job_2006