zoukankan      html  css  js  c++  java
  • 分析模式ORM实现系列——Accountability模式

    本文为分析模式ORM实现系列文章之一。本系列文章使用NBearV3的ORM组件演示Martin Fowler《分析模式——可复用对象模型》一书中列举的可复用分析模型在ORM中的典型实现。本文讨论Accountability模式。

    注:本文演示的ORM实现及全部相关源码,基于即将发布的NBearV3正式版实现,该正式版预计在2006年11月内发布。

    Accountability模式要解决的问题

    在复杂系统中,对象与对象间的关联关系将会非常频繁复杂,参与关联的对象类型可以是人,组织和如合同、职位这样的辅助对象,并且,往往关联关系还有时间约束和其他一些约束规则。例如,员工可以属于一个组织,组织可以由一个人(Leader)负责,人也可以由一个组织负责,人可以有电子邮件,组织也可以有电子邮件等等;再如,对于一个员工属于一个公司这样一个所属关系,它在员工的用工合同有效期间成立,超出合同期限,则失效。

    Accountability模式如何解决这样的复杂关联关系对象的建模呢?

    首先,因为人、组织或辅助对象可能有一些共性的属性,比如,电子邮件,电话,地址等,并且,这些对象互相之间可以有上下级关联,我们可以首先将所有这些共性抽象出一个Party基类。这样Party一方面可以描述所有对象的共性属性,另一方面,可以将对象间的各种关联关系,转化为Party和Party的有约束的自关联。

    接着,因为Party和Party的自关联是有约束的(比如,有效时间约束,上下级关系类型约束等),普通的基于外键关联的1对1、1对多关联无法方便的描述这些约束条件,因此,我们可以引入一个Accoutability对象,专门用来描述一个关联关系。换句话说,一个Accountability对象的实例,描述的是一个二元关联关系,它不仅仅记录关联关系的两端,而且记录关联关系上的约束条件。比较直观的举个例子,它类似我们数据库中常用的带权值的多对多关联,关联关系的约束条件,就相当于权值。

    采用这样一个模型,我们就能很清晰的描述人、组织和辅助对象间带约束的各种复杂关联关系,并且,具有良好的可扩展性。

    ORM实现

    下面,我们使用NBearV3的ORM模块来实现Accountability模式。

    在VS2005 IDE的类图中,我们设计描述了该模式模型的如下框图:



    我们可以看到,首先,Party基类作为Person,Organization和Post这三类对象的基类。XXXData这样的属性,简单的代表任意的属性。Accoutability用于描述有约束条件的关联关系。它有两个主要的约束条件:一个是BeginTime和EndTime——约束了关联关系的有效时间;第二个是Type——约束了这个关联关系的含义,他关联的对象应该各是什么类型。同时,因为我们抽象了Party作为所有对象的基类来描述各种关系,Accoutability的用于描述关联关系的两端的Responsible和Commissioner属性,都是一个Party。

    作为举例,这里还定义了三个Accoutability类型:PersonInOrg代表一个Person在一个Org里;PersonLeadOrg代表Person领导一个Org;PersonOwnPost代表Person拥有的Post。注意,此时,Person的InOrg属性,OwnedPost属性和Organization的OrgLeader属性的类型都是一个Accoutability,因为该属性不仅指定了关联的对象,还包含了关联的约束条件。

    Oranization本身的上下级关联,如果没有约束条件的话,我们可以直接采用自关联来描述。

    下面,您就能看到使用NBear来实现该模型的ORM映射的优势,因为NBear直接基于模型来设计实体关系,我们只需要在以上的模型的对象上,设置描述关联及约束的条件,就能完成所有的OR映射工作,不需要手动写任何XML配置文件,设置几个Attribute就行了。

    我们为所有的实体对象设置如下的Attribute:

      1using System;
      2using System.Collections.Generic;
      3using System.Text;
      4
      5using NBear.Common.Design;
      6
      7namespace AnalysisPatterns.Accountability
      8{
      9    public interface Party : Entity
     10    {
     11        [PrimaryKey]
     12        int ID
     13        {
     14            get;
     15        }

     16
     17        [SqlType("ntext")]
     18        string PartyData
     19        {
     20            get;
     21            set;
     22        }

     23    }

     24
     25    public interface Person : Party
     26    {
     27        [SqlType("ntext")]
     28        string PersonData
     29        {
     30            get;
     31            set;
     32        }

     33
     34        [FkQuery("Commissioner", AdditionalWhere="getdate() >= {BeginTime} AND getdate() < {EndTime} AND {Type} = 1")]
     35        Accoutability InOrg
     36        {
     37            get;
     38            set;
     39        }

     40
     41        [FkQuery("Responsible", AdditionalWhere = "getdate() >= {BeginTime} AND getdate() < {EndTime} AND {Type} = 3")]
     42        Accoutability OwnedPost
     43        {
     44            get;
     45            set;
     46        }

     47    }

     48
     49    public interface Organization : Party
     50    {
     51        [SqlType("ntext")]
     52        string OrgData
     53        {
     54            get;
     55            set;
     56        }

     57
     58        [FkReverseQuery]
     59        Organization ParentOrg
     60        {
     61            get;
     62            set;
     63        }

     64
     65        [FkQuery("ParentOrg")]
     66        Organization[] ChildOrgs
     67        {
     68            get;
     69            set;
     70        }

     71
     72        [FkQuery("Responsible", AdditionalWhere = "getdate() >= {BeginTime} AND getdate() < {EndTime} AND {Type} = 2")]
     73        Accountability OrgLeader
     74        {
     75            get;
     76            set;
     77        }

     78    }

     79
     80    public interface Post : Party
     81    {
     82        [SqlType("ntext")]
     83        string PostData
     84        {
     85            get;
     86            set;
     87        }

     88    }

     89
     90    public interface Accountability : Entity
     91    {
     92        DateTime BeginTime
     93        {
     94            get;
     95            set;
     96        }

     97
     98        DateTime EndTime
     99        {
    100            get;
    101            set;
    102        }

    103
    104        [PrimaryKey]
    105        int ID
    106        {
    107            get;
    108        }

    109
    110        AccountabilityType Type
    111        {
    112            get;
    113            set;
    114        }

    115
    116        [FkReverseQuery]
    117        Party Commissioner
    118        {
    119            get;
    120            set;
    121        }

    122
    123        [FkReverseQuery]
    124        Party Responsible
    125        {
    126            get;
    127            set;
    128        }

    129    }

    130
    131    public enum AccountabilityType
    132    {
    133        PersonInOrg = 1,
    134        PersonLeadOrg = 2,
    135        PersonOwnPost = 3,
    136        OtherTypes = 4,
    137    }

    138}

    您可以注意到,Person的InOrg属性,OwnedPost属性和Organization的OrgLeader属性的Attribute中,描述了读取关联属性时的约束条件。其他Attribute的含义,请参考NBearV3——ORM实体关系设计速查手册

    设置完以上的实体关系和Attribute,就可以使用NBear提供的NBear.Tools.EntityDesignToEntity.exe工具,生成全部的数据库创建脚本和实体代码了。你接下来的所有精力就只需要关注您的业务逻辑,而无需担心ORM过程的细节了。

    //正文结束

    //本文结束

  • 相关阅读:
    autocad.net 利用linq获取矩形框内的块参照
    autocad.net 只在图纸空间遍历块的方法
    autocad.net中判断当前被激活的空间
    计划搞一个程序来应对客户的修改标记问题
    条件编译解决AutoCAD多版本问题
    初学者往往不知道怎么获得断点,请看下面的链接应该可以解决你的问题!
    2014年3月9日正式入住博客园
    学习:SpringCloud(一)
    简单使用:SpringBoot整合Redis
    Redis 使用过程中遇到的具体问题
  • 原文地址:https://www.cnblogs.com/teddyma/p/565669.html
Copyright © 2011-2022 走看看