开发者社区> 吞吞吐吐的> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

微型项目实践(5):Business层代码分析——实体基类

简介:
+关注继续查看

上一篇中,我们分析了Common中的几个类,这几个类都是辅助用的,其实不太重要,重要使我们今天要分析的这几个类,包括Entity、IDatabase、IEntityDataAccess,其中Entity作为所有实体类的基类,更是重中之重,而IDatabase、IEntityDataAccess这两个接口,则是为Entity类服务的。

先看那个熟悉的系统结构图。

system_design

Entity、IDatabase、IEntityDataAccess这三个类型位于Business层中。该层目前的类图如下:

Business

从图中可以看到,Business层包含Blog和BlogClass这两个实体类,他们都继承于Entity类;每个实体类(包括Entity)都对应一个Entension类,这个类自然就是存放该类相关的Extension方法的地方,通常是对IQueryable和IEntityAccess接口的扩展;另外IDatabase和IEntityAccess两个接口定义了数据库访问的方法。

一、Entity类。Entity是所有实体类的基类,是一个模板类不能是结构体的泛型类。它为所有的实体类提供了ID、TimeStamp和IsNew的属性,Validate、Save和Delete方法,每个方法又包含实际操作ValidateAction、SaveAction和DeleteAction。

1,属性:

ID和TimeStamp属性是抽象属性,之所以这样,是因为Linq的继承目前还不是很成熟,所以我们把ID和TimeStamp的具体信息推迟的每个实体类(使用代码生成),这样,对于Linq来说,就是一个不存在继承的实体体系。另外,ID和TimeStamp是只读的,Linq可以通过反射设置字段的内容,所以我们把ID和TimeStamp设置为只读,只由Linq负责这两个字段的值,防止类外部的修改,这一技巧也可以用于其它不允许类外部修改的属性(即只包括get方法的属性)。IsNew方法是基于ID字段判断的,参看以下代码。由于ID是只读的,所以我们可以安全的通过判断ID是否为0来识别该字段是new出来的还是从数据库中读取出来的。

   1:  /// <summary>
   2:  /// 新实体的ID取值
   3:  /// </summary>
   4:  public const int NEW_ENTITY_ID = 0;
   5:  /// <summary>
   6:  /// 取得实体是否是新实体
   7:  /// </summary>
   8:  public bool IsNew
   9:  {
  10:      get { return ID == NEW_ENTITY_ID; }
  11:  }

2,方法:

Entity提供了Validate、Save和Delete三个方法,每个方法又包含可以被子类重写的实际操作:ValidateAction、SaveAction和DeleteAction。两两之间通常是这样子的:

   1:  /// <summary>
   2:  /// 验证
   3:  /// </summary>
   4:  /// <param name="database">数据库</param>
   5:  /// <returns>验证结果</returns>
   6:  public ValidateResult Validate(IDatabase database)
   7:  {
   8:      if (database == null)
   9:          throw new ArgumentNullException("database");
  10:   
  11:      var validater = new Validater();
  12:      ValidateAction(validater, database);
  13:      return validater.Validate();
  14:  }
  15:  /// <summary>
  16:  /// 验证动作
  17:  /// </summary>
  18:  /// <param name="validater">验证器</param>
  19:  /// <param name="database">数据库</param>
  20:  protected virtual void ValidateAction(Validater validater, IDatabase database) { } 

即Validate等入口方法提供了诸如验证参数等得共同操作,而提供给子类可以重写的Action方法。三个方法中比较特别的是Save方法,它在执行Action前,会先调用Validate方法,以保证保存进数据库的数据全部是合法数据。如下:

   1:  public void Save(IDatabase database)
   2:  {
   3:      if (database == null)
   4:          throw new ArgumentNullException("database");
   5:   
   6:      var validateResult = this.Validate(database);
   7:      if (!validateResult.IsValidated)
   8:          throw new ValidateFailException(validateResult);
   9:   
  10:      SaveAction(database);
  11:  }

Validate、Save和Delete所带的参数都是IDatabase接口,这个接口定义了数据库所要实现的全部操作,应该说是一个非常粗颗粒度的接口(虽然现在该接口只有一个方法)。使用粗颗粒度的接口的好处是:实体类内部在处理与自身相关的数据时,可以访问到整个数据库,使用起来方便。从逻辑上讲,这三个方法使用数据库作为参数,表示在该数据上下文环境中,执行Validate、Save和Delete操作,意思也是很清晰的。后面会出现的对于数据库的操作,都将以这种粗颗粒度的接口作为参数。不过使用粗颗粒度的接口也要注意,实现机制不能过于臃肿,不然构造太多的实例会影响系统性能,我们使用Lazy Load解决这个问题,在分析数据访问的实现时,我们还会回到这个问题上来。

EntityExtension这个类提供了一个非常常用的扩展方法:根据ID取得实体:

   1:  /// <summary>
   2:  /// 根据ID取得实体
   3:  /// </summary>
   4:  /// <typeparam name="T">实体类型</typeparam>
   5:  /// <param name="query">实体查询</param>
   6:  /// <param name="id">ID</param>
   7:  /// <returns>对应的实体,不存在则返回空</returns>
   8:  public static T GetByID<T>(this IQueryable<T> query, int id)
   9:      where T : Entity<T>
  10:  {
  11:      if (query == null)
  12:          throw new ArgumentNullException("query");
  13:   
  14:      return query.SingleOrDefault(entity => entity.ID == id);
  15:  }

有了这个方法,结合数据访问接口,就可以通过这样的方式取得一个Blog:database.GetDataAccess<Blog>().GetByID(1);

该方式,以后还会进一步简化为:database.Blogs.GetByID(1);

今天我们分析了实体基类的代码和设计方式,下一篇中我们将着重研究数据访问两个接口的设计与实现。

代码下载

本文转自冬冬博客园博客,原文链接:http://www.cnblogs.com/yuandong/archive/2008/05/08/1188936.html,如需转载请自行联系原作者

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
网站漏洞检测 wordpress sql注入漏洞代码审计与修复
wordpress系统本身代码,很少出现sql注入漏洞,反倒是第三方的插件出现太多太多的漏洞,我们SINE安全发现,仅仅2019年9月份就出现8个插件漏洞,因为第三方开发的插件,技术都参差不齐,对安全方面也不是太懂导致写代码过程中没有对sql注入,以及xss跨站进行前端安全过滤,才导致发生sql注入漏洞。
231 0
原创C# Winform+DevExpress皮肤框架
作为.NET快速开发框架首选产品,C/S框架网专注研发基于C# Winform皮肤框架,借助DevExpress三方组件提供的强大界面功能、顶级的外观表现以及专业的用户体验
8060 0
CSS魔法堂:更丰富的前端动效by CSS Animation
在[《CSS魔法堂:Transition就这么好玩》](https://www.cnblogs.com/fsjohnhuang/p/9143035.html)中我们了解到对于简单的补间动画,我们可以通过`transition`实现。
1279 0
Linux下使用Aliyun OSS C SDK
详细说明了Linux下如何编译运行基于OSS C SDK的C/C++程序,附件中提供了基于Makefile的示例工程。
11154 0
C# WinForm登录窗口代码
Main窗体为应用程式主窗体,Login为登录窗体。均为SDI窗体。     两种实现方式如下:   1、应用程式入口放在Login窗体,在Login窗体实现登录机制,验证通过则创建Main窗体的实例,并将自身隐藏。
834 0
C#实现WinForm窗口最小化到系统托盘
引用:http://www.cnblogs.com/xugang/archive/2007/12/19/1006005.html 1.设置WinForm窗体属性showinTask=false 2.加notifyicon控件notifyIcon1,为控件notifyIcon1的属性Icon添加一个icon图标。
746 0
前端代码标准最佳实践:CSS篇
上一篇《前端代码标准最佳实践:javascript》发表后,大家讨论还是很热烈,从侧面体现了前端工程师对写标准的前端代码的重视程度很高。这些最佳标准实践并不是那个权威组织发布的,而是由大量的前端工程师们在实践过程中的经验总结,目的在于提高代码的可读性,可维护性和性能。
1016 0
4849
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载