連載
» 2015年04月01日 05時00分 UPDATE

.NET TIPS:AutoMapperを使って異なるオブジェクト間のデータコピーを自動化するには?(名前変換ルール編)

データの転送元と転送先のプロパティ名に一定の変換ルールがある場合に、AutoMapperによりデータコピーを自動化する方法を解説する。

[山本康彦,BluewaterSoft/Microsoft MVP for Windows Platform Development]
.NET TIPS
Insider.NET

 

「.NET TIPS」のインデックス

連載目次

対象:.NET 4以降


 オープンソースのライブラリ「AutoMapper」を使うと、異なるクラス間のデータコピーを自動化できる。「独自マッピング編」ではプロパティ名が異なるときに独自のマッピングを定義する方法を紹介した。しかし、例えばデータベースの多数の列名をマッピングするコードを書くのは、うんざりする作業だ。何とかならないだろうか? データベースの列名とコピー先のプロパティ名の間に一定の名前変換規則があれば、そのルールに基づいてAutoMapperにマッピングさせることができるのだ。本稿では、そのようなAutoMapperのマッピング機能の使い方を紹介する。

 なお、本稿執筆時点でAutoMapperがサポートしているのは.NET Framework 4以降であるが、NuGetから導入するため、本稿ではVisual Studio 2012を使って説明する。また、本稿のサンプルは「MSDN Code Recipe:.NET Tips #1104」からダウンロードできる。

AutoMapperを導入するには?

 「.NET TIPS:AutoMapperを使ってオブジェクト間のデータコピーを自動化するには?(基本編)」をご覧いただきたい。

例題

 ここでは例題として、催事の情報を格納してあるデータベースがあって、データベースにSQLを発行して得られた結果を型付きデータセットに格納しているものとしよう。その型付きデータセットは「EventDataSet」クラスとして、次の画像と表に示すように定義してある。この中に定義した「EventTable」クラスをデータのコピー元とする。

型付きデータセット「EventDataSet」クラスの編集画面(Visual Studio 2012) 型付きデータセット「EventDataSet」クラスの編集画面(Visual Studio 2012)
Visual Studio 2012で型付きデータセットを編集している画面の一部である。
型付きデータセットを作成するには、プロジェクトに新しい項目を追加するダイアログで[データセット]を選び、ファイル名を「EventDataSet.xsd」とする。作成したファイルを開いた画面の中を右クリックし、そのメニューから[追加]−[DataTable]を選ぶと、画面上にDataTableの定義が追加される。そのDataTableの名前を「EventTable」に変更する。また、DataTableを右クリックして出てくるメニューの[追加]−[列]を使って、データ列の定義を追加してプロパティを設定する(次の表)。
なお、実際の開発では、データベースエクスプローラーから目的のテーブルを型付きデータセットの編集画面にドラッグ&ドロップするだけで、このようなDataTableの定義が自動的に生成される。そのとき生成される列名はデータベースに定義されている名前になる。

列名 型(DataTypeプロパティ)
event_id System.UInt16
event_title System.String
date_time System.DateTime
型付きデータセット「EventDataSet」内の「EventTable」クラスの列定義

 また、データのコピー先は、次のコードのような「EventData」クラスとする。

public class EventData
{
  public DateTime DateTime { get; set; }
  public string EventTitle { get; set; }

  public static IList<EventData> GetData()
  {
    // 後述
  }
}

Public Class EventData
  Public Property DateTime As DateTime
  Public Property EventTitle As String

  Public Shared Function GetData() As IList(Of EventData)
    ' 後述
  End Function
End Class

ロジックで使う「EventData」クラスの例(上:C#、下:VB)
「EventTitle」と「DateTime」という二つのプロパティを持つシンプルなクラスである。
この二つのプロパティに、型付きデータセットの「EventTable」オブジェクトから値をコピーしたいのだ。以降で、その実装を「GetData」メソッド内に行う(ここでは「// 後述」としてある部分)。
なお、このVBのコードでは、Visual Basic 2005からの機能であるジェネリック型や、Visual Basic 2010から利用できるようになった自動実装プロパティを使用している。

 以上の二つのクラスのオブジェクト間で、次の図のようなデータコピーを行いたいのである。ここではコピー対象のプロパティが二つだけだが、実際の開発では何十個もあったりすることが珍しくないだろう。

本稿で実装するデータマッピング 本稿で実装するデータマッピング
EventTableクラス(左)とEventDataクラス(右)で、コピーしたいプロパティの名前の間に一定の変換ルールがある。単語の区切りであるアンダースコア「_」を削除し、代わりに単語の先頭を大文字にする(=Pascal形式)、という変換規則だ。
AutoMapperで名前変換ルールを適用することにより、この図に示したようなコピーが簡単にできる。

AutoMapperで名前変換ルールを適用するには?

 AutoMapperのInitializeメソッドで名前変換ルールを指定すればよい。

 名前変換ルールは、INamingConventionインターフェース(AutoMapper名前空間)を実装したクラスとして定義する。ただし上の例題の場合は、すでに用意されている名前変換クラスが利用できる。データのコピーを前述した「EventData」クラスの「GetData」メソッドで行うには、次のコードのようになる。

public static IList<EventData> GetData()
{
  // データベースからデータを取得してくる
  // (ここではその代わりに、仮のデータをハードコーディングしている)
  EventDataSet ds = new EventDataSet();
  EventDataSet.EventTableDataTable dt = ds.EventTable;
  dt.AddEventTableRow(1, event_title: "とっておきイベント☆その1",
                          date_time: new DateTime(2015, 3, 31, 15, 0, 0));
  dt.AddEventTableRow(2, event_title: "とっておきイベント☆その2",
                          date_time: new DateTime(2015, 4, 30, 0, 30, 0));
  dt.AddEventTableRow(3, event_title: "とっておきイベント☆その3",
                          date_time: new DateTime(2015, 5, 26, 10, 0, 0));

  // AutoMapperを使って、型付きデータセットをこのクラスのリストに変換する
  // まず、プロパティ名の名前変換ルールを指定する
  AutoMapper.Mapper.Initialize(cfg =>
  {
    // 変換元のプロパティ名が、小文字をアンダースコアでつなげた形式
    // (例:「event_title」)であるときに…、
    cfg.SourceMemberNamingConvention
      = new AutoMapper.LowerUnderscoreNamingConvention();
    // 変換先のプロパティ名として、パスカル形式(例:「EventTitle」)を探させる
    cfg.DestinationMemberNamingConvention
      = new AutoMapper.PascalCaseNamingConvention();
  });
  // 後は、基本編で説明したようにCreateMapしてMapするだけ
  AutoMapper.Mapper.CreateMap<EventDataSet.EventTableRow, EventData>();
  return AutoMapper.Mapper.Map<List<EventData>>(dt);
}

Public Shared Function GetData() As IList(Of EventData)
  ' データベースからデータを取得してくる
  ' (ここではその代わりに、仮のデータをハードコーディングしている)
  Dim ds As EventDataSet = New EventDataSet()
  Dim dt As EventDataSet.EventTableDataTable = ds.EventTable
  dt.AddEventTableRow(1, event_title:="とっておきイベント☆その1",
                         date_time:=New DateTime(2015, 3, 31, 15, 0, 0))
  dt.AddEventTableRow(2, event_title:="とっておきイベント☆その2",
                         date_time:=New DateTime(2015, 4, 30, 0, 30, 0))
  dt.AddEventTableRow(3, event_title:="とっておきイベント☆その3",
                         date_time:=New DateTime(2015, 5, 26, 10, 0, 0))

  ' AutoMapperを使って、型付きデータセットをこのクラスのリストに変換する
  ' まず、プロパティ名の名前変換ルールを指定する
  AutoMapper.Mapper.Initialize(
    Sub(cfg)
      ' 変換元のプロパティ名が、小文字をアンダースコアでつなげた形式
      ' (例:「event_title」)であるときに…、
      cfg.SourceMemberNamingConvention _
        = New AutoMapper.LowerUnderscoreNamingConvention()
      ' 変換先のプロパティ名として、パスカル形式(例:「EventTitle」)を探させる
      cfg.DestinationMemberNamingConvention _
        = New AutoMapper.PascalCaseNamingConvention()
    End Sub)
  ' 後は、基本編で説明したようにCreateMapしてMapするだけ
  AutoMapper.Mapper.CreateMap(Of EventDataSet.EventTableRow, EventData)()
  Return AutoMapper.Mapper.Map(Of List(Of EventData))(dt)
End Function

名前変換ルールを使ってコピーする例(上:C#、下:VB)
太字の部分が、名前変換ルールを指定しているコードである。Initializeメソッドの引数として渡しているのはラムダ式だ*1
なお、このVBのコードでは、Visual Basic 2005からの機能であるジェネリック型や、Visual Studio 2010から導入された「暗黙の行連結」機能を使用している。

*1 ラムダ式について詳しくは、次のMSDNのドキュメントを参照していただきたい。


実行結果

 別途公開のサンプルを実行している様子を次の画像に示す。このサンプルではAutoMapperを使って、「EventTable」クラス→「EventData」クラス→「EventDataForDisplay」クラスという2段階のデータコピーを行っている(後半のコピー方法は「独自マッピング編」を参照)。

例題のクラスを使ってWPFの画面にデータを表示した例(Visual Studio 2012) 例題のクラスを使ってWPFの画面にデータを表示した例(Visual Studio 2012)
これはデバッグ実行しているところである。実際のコードは、別途公開のサンプルをご覧いただきたい。

まとめ

 本稿ではINamingConventionインターフェースの実装方法を説明しなかったが、正規表現が分かっていればそれほど難しくない。本稿の例とは異なる名前変換ルールの場合はINamingConventionインターフェースの実装が必要になるかもしれないが、ぜひチャレンジしてみてほしい。

 AutoMapperにはまだ多くの機能があり、適用範囲はさらに広い。そのドキュメントは英語だが、読み解いてみる価値はあるだろう。

カテゴリ:オープンソース・ライブラリ 処理対象:データ型
カテゴリ:C# 処理対象:データ型
カテゴリ:Visual Basic 処理対象:データ型
関連TIPS:AutoMapperを使ってオブジェクト間のデータコピーを自動化するには?(基本編)
関連TIPS:AutoMapperを使ってオブジェクト間のデータコピーを自動化するには?(独自マッピング編)


「.NET TIPS」のインデックス

.NET TIPS

Copyright© 1999-2017 Digital Advantage Corp. All Rights Reserved.

@IT Special

- PR -

TechTargetジャパン

この記事に関連するホワイトペーパー

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。