VB のたまご

作成日: 2015/12/03, 更新日: 2015/12/03


型無し DataRow をデータクラスに変換してみた( VB.NET 版)

うーん、困った。

  •  Entity Framework が主流と言われる昨今ですが、今更 DataRow のお話です。
  • ずうっと、DataSet を使い続けてきた私にとって、簡単に準備できるテストデータは DataSet でこしらえることが多い日々です。 DataSet を使うなら、型無し DataSet ではなく型付 DataSet の方が、扱いが楽ですよね。 でも皆さんが言うように、型付 DataSet は何でもかんでも搭載しているし、壊れることもあるし、よろしくないよねーというのも分かります。

  •  普段簡単に扱うなら、作るのが楽な 型無し DataSet なわけですが、使うときは、やっぱりフィールド指定が面倒くさい面倒くさい。 インテリセンスでさくっといかないものかと、あれこれ考えました。


スポンサーリンク


対処案その1、匿名型のデータクラスに変換して使う。

  •  この対処案は、匿名型とオブジェクト初期化子と型推論を使ったものです。
  • Dim dt As New DataTable("SampleTable")
    dt.Columns.AddRange(New DataColumn() {
                        New DataColumn("ID", GetType(Integer)),
                        New DataColumn("Name", GetType(String))
                        })
    
    dt.Rows.Add(New Object() {1, "aaa"})
    dt.Rows.Add(New Object() {2, "bbb"})
    dt.Rows.Add(New Object() {3, "ccc"})
    
    For Each row As DataRow In dt.Rows
    
        Dim user = New With {.ID = row.Field(Of Integer)("ID"),
                             .Name = row.Field(Of String)("Name")}
    
        Console.WriteLine("ID = {0}, Name = {1}", user.ID, user.Name)
    
    Next
    

  •  しかし、これはボツです。
  • 一応、インテリセンスのサポートが効くので、楽にフィールド指定ができるのですが、 わざわざ自前で匿名型のデータクラス作らないといけないのは手間だよねーというのと、 作っている最中に、フィールド名を打ち間違う可能性もあるし、 というか、そういうのを無くしたいから、考えているんじゃん。ということで、ボツとなりました。

  •  変換処理は自動的であるべき、というのと、戻り値もテーブルのフィールドに合わせて動的に生成、というのを目標にしていました。 しかし、結局この2点に叶う実現方法は見つけられませんでした。


スポンサーリンク


対処案その2、定義した型のデータクラスに変換して使う。

  •  探しているうちに、山本大さんの記事を見つけて、おーこれだー!という結論になりました。 つまり、変換処理は自動的に行うのですが、変換後のデータクラスは、あらかじめ定義しておいてね。という仕様です。 本当は、あらかじめ定義しなくても、リフレクションとDataRow.DataTable.DataColumns 見て、 変換後のデータクラスを自動生成したかったので、なんとかならないかなーと考えていたんですが、 なんとかなりませんでした><。

  •  ちなみに対応策は、リフレクションとジェネリックと拡張メソッドの知識を持っている前提な話になりますが、 別によく分からなくてもいいような気もします。面倒見てあげる部分は一回作ったら放置で良いし、使い方の部分は、見たら分かりそうな感じかなと思います。
  • Imports System.Runtime.CompilerServices
    Imports System.Reflection
    
    Module DataRowExtensions
    
        <Extension()>
        Public Function GetRowData(Of TClass As New)(target As DataRow) As TClass
    
            Dim resultData As New TClass
            Dim t As Type = resultData.GetType
            Dim pis() As PropertyInfo = t.GetProperties
    
            For Each pi As PropertyInfo In pis
                pi.SetValue(resultData, target(pi.Name))
            Next
    
            Return resultData
    
        End Function
    
    End Module
    
    ' DataTable に対応するデータクラスの定義
    Class MemberData
        Public Property ID As Integer = 0
        Public Property Name As String = String.Empty
    End Class
    
    Dim dt As New DataTable("SampleTable")
    dt.Columns.AddRange(New DataColumn() {
                        New DataColumn("ID", GetType(Integer)),
                        New DataColumn("Name", GetType(String))
                        })
    
    dt.Rows.Add(New Object() {1, "aaa"})
    dt.Rows.Add(New Object() {2, "bbb"})
    dt.Rows.Add(New Object() {3, "ccc"})
    
    For Each row As DataRow In dt.Rows
    
        Dim user As MemberData = row.GetRowData(Of MemberData)()
        Console.WriteLine("ID = {0}, Name = {1}", user.ID, user.Name)
    
    Next
    

  •  うーん、楽だ~。

  •  最後までこの記事を読んでいただき、ありがとうございました。

  • スポンサーリンク