DXO (Data eXchange Object) とは,PONO(Plain Old NET Object)とPONO、PONOとCollection、PONOとDictionaryを相互変換 (exchange)することを目的としたオブジェクトです.主な用途としては,プレゼンテーション層のモデル (ページ) とドメイン層のモデル (エンティティ) を相互変換することを意図しています.

S2DxoはDXOを実現するためのフレームワークです.S2Dxoを使うと,インタフェースを定義するだけで DXOを実現することが可能となります.

 

さっそく試してみましょう.登場人物はC#の場合、次のようになります.

変換元のPONO
EmployeeとDepartmentの二つ.EmployeeはDepartmentを参照します.

変換先のPONO
EmployeePage.EmployeePageはEmployeeとDepartmentの両方のプロパティを持っています.

変換を行うDXO
EmployeeDxo.EmployeeとDepartmentをEmployeePageに変換するDXOのインタフェースです.

S2Dxoは,上記3つのPONOに対して,以下の図のような変換を行います.

 

Employee.cs

変換元のPONOです.Departmentを参照します.

namespace Seasar.Tests.Dxo 
{
    public class Employee
    {
        private Department _department;
        private string _ename;

        public string EName
        {
            get { return _ename; }
            set { _ename = value; }
        }

        public Department Department
        {
            get { return _department; }
            set { _department = value; }
        }
    }
}

 

Department.cs

変換元のPONOです.Employeeから参照されます.

namespace Seasar.Tests.Dxo 
{
    public class Department
    {
        private string _dname;

        public string DName
        {
            get { return _dname; }
            set { _dname = value; }
        }
    }
}

 

EmployeePage.cs

変換先のPONOです.EmployeeのプロパティENameに加えて,DepartmentのプロパティDepartmentも 持っています.

namespace Seasar.Tests.Dxo 
{
    public class EmployeePage
    {
        private string _dname;
        private string _ename;

        public string Department
        {
            get { return _dname; }
            set { _dname = value; }
        }

        public string EName
        {
            get { return _ename; }
            set { _ename = value; }
        }
    }
}

 

IEmployeeDxo.cs

変換を行うDXOです.引数として変換元のPONOであるEmployeeを受け取り,戻り値として 変換先のPONOであるEmployeePageを返します.単なるインタフェースで実装がないことに 注目してください.

また、逆にEmployeePageからEmployeeへの変換も出来ます

namespace Seasar.Tests.Dxo 
{
    public interface IEmployeeDxo
    {
        EmployeePage ConvertToEmployeePage(Employee emp);

        void ConvertPageToEmp(EmployeePage page, Employee emp);
    }
}

 

app.dicon

EmployeeDxoを利用するために必要な設定を記述します.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
"http://www.seasar.org/dtd/components21.dtd">
<components namespace="dxo">
    <!-- インターセプタ -->
    <component name="interceptor" class="Seasar.Dxo.Interceptor.DxoInterceptor"/>

    <!-- コンポーネント -->
    <component class="Seasar.Tests.Dxo.IEmployeeDxo">
        <aspect pointcut="*">interceptor</aspect>
    </component>
</components>

 

実行クラスの中では次のように記述します.

[Test, S2]
public void TestSimple()
{
        Include(PATH);
        IEmployeeDxo dxo = (IEmployeeDxo) GetComponent(typeof (IEmployeeDxo));

        Employee employee = new Employee();
        employee.EName = "Mike";
        Department dept = new Department();
        dept.Department = "Sales";
        employee.Department = dept;

        EmployeePage page = dxo.ConvertToEmployeePage(employee);
        Assert.AreEqual("Mike", page.EName, "EName");
        Assert.AreEqual("Sales", page.Department, "Department");
        if (!String.IsNullOrEmpty(page.Name))
            Assert.Fail("Name2");

}

 

インターフェイス定義

 Dxoは通常インターフェイスとして定義します。

 次のようになります。

C#

public interface IFooDxo
{
	...
}

VB

Public Interface IFooDxo
	...	   
End Interface

 

メソッド定義

 Dxoには変換を行うメソッドを定義します。メソッド名は自由に定義できますが、 慣例的にConvertで始めます。

DXOのメソッドは次の2つの形式のいずれかにすることができます。

  • 変換先型  メソッド名(変換元型)
  • void  メソッド名(変換元型, 変換元型)

 戻り値が変換後型の場合はS2Dxo.NETがインスタンスを生成して返します。 戻り値がvoidの場合は第2引数で受け取ったインスタンスを更新します。

変換前及び変換後の型の組み合わせは次のものがサポートされています。

変換前型変換後型
PONOPONO
PONO[]PONO[]
PONOSystem.Collections.Generic.IList<PONO>
System.Collections.Generic.IList<PONO> System.Collections.Generic.IList<PONO>
PONOSystem.Collections.IDictionary
System.Collections.IDictionaryPONO

例えば次のようになります。

C#

public interface IFooDxo
{
        void ConvertPonoToPono(FromBean fromBean, ToBean toBean);
        ToBean ConvertToPono(FromBean fromBean);

        void ConvertFromArrayToArray(FromBean[] fromArray, ToBean[]toArray);
        ToBean[] ConvertToArray(FromBean[] fromArray);

        void ConvertListToList(IList<FromBean> fromArray, IList<ToBean> toArray);
        List<ToBean> ConvertToList(IList<FromBean> toArray);

        void ConvertToDictinary(FromBean emp, IDictionary dict);
        void ConvertFromDictionaryToPONO(IDictionary dict, FromBean emp);

}

  

インターセプタの適用

DXOインタフェースにはS2Dxo.NETの提供するインターセプタを適用します

<components namespace="dxo">
    <!-- インターセプタ -->
    <component name="interceptor" class="Seasar.Dxo.Interceptor.DxoInterceptor"/>
</components>

 

変換の基本

 PONOまたはIDictionaryからPONOに変換する場合,変換先となるPONOのプロパティを変換元から探し, (必要なら)型変換を行って変換先のプロパティに設定します.

 PONOからIDicitionaryに変換する場合は,変換元のPONOの全プロパティについて変換先の IDictionaryに追加します.追加されるエントリのキーは変換元のプロパティ名(string),値は変換元のプロパティ値です.

 

型変換

 変換元と変換先の型が異なる場合は型変換が行われます.S2Dxoが標準で提供する型変換は以下の通りです.変換先の型を基準に参照してください.

変換元の型変換先の型説明
boolbool-
short, int, long1以上であればtrue, それ以外はfalseに変換.
その他任意の型 変換元を文字列化し、それが"yes", "y", "true", "on", "1"の
いずれかならばtrue, そうでなければfalseに変換
boolshort, int, long 変換元がtrueなら1,そうでなければ0に変換.
short, int, long同等の値に変換します.
string文字列の表現する数値と同等の値に変換します.
charchar-
stringstring-
char[]変換元を文字シーケンスとして持つstringに変換します.
System.DataTimeDatePattern属性に従い変換します.
詳細は「日付・時刻のフォーマット」を参照してください.
char[]char[]-
string変換元の持つ文字配列に変換します.
System.DateTimeSystem.DateTime-
long変換元のlong値を時刻値として持つSystem.DateTimeに変換します.
stringDatePattern属性に従いSystem.DateTimeに変換します.
詳細は「日付・時刻のフォーマット」を参照してください.
PONOPONO変換元PONOを変換先PONOに変換します.
変換元PONOのプロパティは変換先PONOの対応するプロパティに変換されます.

 

 変換先のPONOに存在するプロパティと同名のプロパティが変換元のPONOに存在しない場合, S2DxoはネストしたPONOのプロパティを探します.ネストしたPONOのプロパティとは, 変換元PONOが持つPONOを型とするプロパティのプロパティです.

 この探索はJava版と同様に一段階のみ行われます.

C#

public class Employee
{
    private  Department _department;
    public Department Dept
    {
       get { return _department; }
       set { _department = value; }
    }
	...
}

public class Department
{
    private  string _dname;
    public string DName
    {
       get { return _dname; }
       set { _dname = value; }
    }
	...
}

public class EmployeePage
{
    private  string _dname;
    public string DName
    {
       get { return _dname; }
       set { _dname = value; }
    }
	...
}

 上の例で,EmployeeからEmployeePageへの変換を行うと,EmployeePageのDNameプロパティには,      EmployeeのDeptプロパティが参照する,DepartmentのDNameプロパティが設定されます.

 

変換元プロパティの指定

 変換元PONOまたはマップのプロパティ名と変換先PONOまたはマップのプロパティ名が 異なる場合は属性で変換ルールを指定することができます.

変換元のプロパティと変換先のプロパティをSeasar.Dxo.Annotation.ConversionRuleAttributeで指定します.

例えば次のようになります。

C#

public interface IFooDxo
{
    [ConversionRule(PropertyName = "EName", TargetPropertyName = "DName")]
    [ConversionRule("DName","EName")]
    ToBean ConvertBeanToTarget(FromBean source);
}

VB

Public Interface IFooDxo
    <ConversionRule(PropertyName = "EName", TargetPropertyName = "DName")> _
    <ConversionRule("DName","EName")> _
    Function ConvertBeanToTarget(ByVal source As FromBean) As ToBean
End Interface

 

日付時刻のフォーマット

 System.DateTimeとstringとの相互変換を行う場合にはフォーマットパターンを指定できます.

 フォーマットパターンは解釈することができるパターン文字列で,DXOインタフェースのメソッドにSeasar.Dxo.Annotation.DatePatternAttributeで指定することができます.属性が指定されたメソッドで行われる変換の際に,PONOのプロパティにSystem.DateTimeとstringとの変換が必要になると,指定されたフォーマットパターンが使われます.フォーマットパターンが指定されなかった場合は,デフォルトロケールのデフォルトパターンが使われます.

例えば次のようになります。

C#

public interface IFooDxo
{
    [DatePattern("yyyyMMdd")]
    ToBean ConvertBeanToTarget(FromBean source);
}

VB

Public Interface IFooDxo
    <DatePattern("yyyyMMdd")> _
    Function ConvertBeanToTarget(ByVal source As FromBean) As ToBean
End Interface

 Seasar.NET 1.4.0, 1.3.19以降では、DxoInterceptorをスレッドセーフにする対応のため、下記プロパティ、メソッドが変更になっています。
 Seasar.Dxo.Interceptor.DxoInterceptorを拡張してご利用している場合はご注意下さい。

  • DxoMappingプロパティ ⇒ 廃止
  • AssignFromArrayToArrayメソッド ⇒ シグネチャ変更
  • AssignFromListToListメソッド ⇒ シグネチャ変更
  • AssignFromObjectToListメソッド ⇒ シグネチャ変更
  • AssignToメソッド ⇒ シグネチャ変更
  • _CollectConversionRuleAttributeメソッド ⇒ シグネチャ変更
  • _TryExchangeSameNamePropertyメソッド ⇒ シグネチャ変更
  • _ConvertPropertyメソッド ⇒ シグネチャ変更
  • _CollectDatePatternMappingメソッド ⇒ GetDataPatternFormatに名称変更、シグネチャ変更
  • CreateDxoMappingメソッド(protected, 拡張可) ⇒ 新規追加