2012年6月25日月曜日

VB.NETでCSV読まないといけなくなった

どうやってやるのがいいの?

社員のモデル
Public Class Syain
    '社員コード
    Private mCode As String
    '社員氏名
    Private mName As String

    Public Property Code As String
        Get
            Code = mCode
        End Get
        Set(value As String)
            mCode = value
        End Set
    End Property

    Public Property Name As String
        Get
            Name = mName
        End Get
        Set(value As String)
            mName = value
        End Set
    End Property

    Public Overrides Function ToString() As String
        Return "code: " & mCode & ", name: " & mName
    End Function

End Class

社員のMapper
Public Class SyainMapper
    Inherits CsvMapper

    'カラム名とプロパティ名のマッピング
    Private Shared MAPPINGS As New SortedDictionary(Of String, String) From { _
            {"社員コード", "Code"}, _
            {"社員氏名", "Name"}}

    Protected Overrides Function GetMappings() As SortedDictionary(Of String, String)
        GetMappings = MAPPINGS
    End Function

    'モデルの名前とテーブル名は一致させること
    Protected Overrides Function GetModel() As Type
        GetModel = GetType(Syain)
    End Function

End Class

Mapperの共通部分
Imports System.Data.OleDb

Public Class CsvMapper

    '接続先(CSV用)
    Private Shared connectionString As String = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
              "Data Source=C:\tmp\;" & _
              "Extended Properties=""Text;HDR=YES;FMT=Delimited"""

    'SELECT文
    Private Function selectSQL() As String
        '個別のカラム情報を取得
        Dim columns As String() = (From i As String In GetMappings().Keys Select i).ToArray()
        'テーブル名、カラム名からSELECT文を構築
        selectSQL = "SELECT " & Join(columns, ",") & " FROM " & GetModel.Name() & ".csv"
    End Function

    'SELECT文を実行して一覧を返す
    Public Function List() As IList
        List = New ArrayList()
        Using connection As New OleDbConnection(connectionString)
            Dim command As New OleDbCommand(selectSQL, connection)
            connection.Open()
            Dim reader As OleDbDataReader = command.ExecuteReader()
            While reader.Read()
                List.Add(Transform(reader))
            End While
            reader.Close()
        End Using
    End Function

    'レコードをモデルに変換する
    Protected Overridable Function Transform(reader As OleDbDataReader) As Object

        'サブクラスからモデル情報を取得
        Dim modelType As Type = GetModel()
        If IsNothing(modelType) Then
            'モデル情報がなければHashtableに入れて返す
            Dim obj As New Hashtable
            Dim idx As Integer = 0
            For Each key As String In GetMappings.Values
                obj(key) = reader(idx)
                idx = idx + 1
            Next
            Transform = obj
        Else
            'モデル情報があればインスタンスを生成してプロパティを設定して返す
            Dim obj As Object = modelType.InvokeMember("New", Reflection.BindingFlags.CreateInstance, Nothing, Nothing, Nothing)
            Dim idx As Integer = 0
            For Each key As String In GetMappings.Values
                modelType.InvokeMember(key, Reflection.BindingFlags.SetProperty, Nothing, obj, New Object() {reader(idx)})
                idx = idx + 1
            Next
            Transform = obj
        End If
    End Function

    Protected Overridable Function GetModel() As Type
        GetModel = Nothing
    End Function

    Protected Overridable Function GetMappings() As SortedDictionary(Of String, String)
        Throw New NotImplementedException
    End Function

End Class

0 件のコメント: