AdventureWorksをモデリングしてDDDしながらドメインモデルで実装してみる(7)

今回から分析した従業員エンティティをドメインモデルで実装していきます。

Castle ActiveRecordを使ってみる

今回の実装で利用するORマッパーは何にしようか悩んだのですが、マッピングの自由度やプログラムの対応のわかり易さなどを考えてCastle ActiveRecordを利用します。Castle ActiveRecordNHibernate上で作成されていてRoRの影響を受けています。いままで気になっていたので今回初めてですが利用します。

クラスをテーブルにマッピングする

Castle ActiveRecordでのマッピング指定は属性を利用します。見ればどのようなマッピングかイメージできると思います。従業員(Employee)クラスのマッピングですがかなりいろいろなパターンを必要としましたが、分析した構造でそのままマッピングできました。*1

[ActiveRecord(Schema = "HumanResources")]
public class Employee : ActiveRecordBase<Employee>
{
    [PrimaryKey]
    public virtual int EmployeeID { get; set;}

    [Property]
    public virtual String NationalIDNumber { get; set;}

    [BelongsTo("ContactID")]
    public virtual Contact Contact { get; set; }

    [BelongsTo("ManagerID")]
    public virtual Employee Manager { get; set; }

    [Nested]
    public virtual EmployeeTitle Title { get; set; }

    [Property(Column = "MaritalStatus")]
    protected virtual string DBMaritalStatus { get; set; }

    public virtual MaritalStatus MaritalStatus
    {
        get { return DBMaritalStatus == "M" ? MaritalStatus.Married : MaritalStatus.Single ; }
        set { DBMaritalStatus = (value == MaritalStatus.Married ? "M" : "S") ; }
    }

    [HasMany(typeof(EmployeeDepartmentHistory),Table="EmployeeDepartmentHistory",
        ColumnKey="EmployeeID")]
    public IList<EmployeeDepartmentHistory> DepartmentHistory { get; protected set; }

    [HasAndBelongsToMany(typeof(Address), Schema = "HumanResources", Table = "EmployeeAddress", 
                            ColumnKey = "EmployeeID", ColumnRef = "AddressID")]
    public IList<Address> Addresses { get; protected set; }

    ...

マッピングができれば、あとはビジネスルールから識別した項目を実装してドメインモデルが完成します。このコードを利用してあとは機能を実装していきます。もちろん必要に応じてモデルを発展させていきます。

    public Shift CurrentShift
    {
        get { return RecentDepartmentHistory.Shift; }
    }

    public Department CurrentDepartment
    {
        get { return RecentDepartmentHistory.Department; }
    }

    protected EmployeeDepartmentHistory RecentDepartmentHistory
    {
        get 
        {
            if (DepartmentHistory.Count == 0) 
       return EmployeeDepartmentHistory.NullEmployeeDepartmentHistory;
            foreach (EmployeeDepartmentHistory h in DepartmentHistory)
            {
                if (h.EndDate != null) return h;
            }
            return DepartmentHistory[0];
        }
    }

実際のコードをリバースしたクラス図(Visual Studio版)は以下のようになります。分析モデルと同じ構造になっています。

*1:直接マッピング難しい場合はマッピングしたプロパティの導出項目として実装しています