WPF開発ノウハウ集

Entityクラスの利用

既に照会した方法ではデータベースから取得した情報をDictionary<string, object>で保持していたが、それではobjectを必要に応じてキャストする必要があったりして扱いにくいので、テーブルの型を模したEntityクラスにデータベースから取得したデータを入れて保持する


Entityクラスの実装例


リフレクションを利用してEntityクラスにデータを入力する

リフレクションによるデータ入力の手順は下記のとおり:

  1. データベースから取得したデータのフィールド名をキャメリング
  2. リフレクションにより、キャメリングされたフィールド名および取得データ型と一致するEntityのプロパティに取得データを入力


キャメリングを行う関数の実装例

/// <summary>
/// スネークケース(_区切りの文字列)をキャメルケースにして返します
/// </summary>
/// <param name="str">変換前の文字列</param>
/// <returns>変換後の文字列</returns>
public static String ToCamelCase( string str )
{
    string lowerCase = str.ToLower();
    string[] item = lowerCase.Split( new char[] { '_' } );
    StringBuilder builder = new StringBuilder( item[0] );
    for( int _i = 1; _i < item.Length; _i++ )
    {
        builder.Append( Capitalize( item[_i] ) );
    }
    return builder.ToString();
}

/// <summary>
///  引数の先頭文字のみを大文字にして返します
/// </summary>
/// <param name="str">変換前の文字列</param>
/// <returns>変換後の文字列</returns>
private static string Capitalize( string str ) {
    if( string.IsNullOrEmpty( str ) ) 
    {
        return str;
    }

    return new StringBuilder( str.Length )
            .Append( str.Substring( 0, 1 ).ToUpper() )
            .Append( str.Substring( 1 ) )
            .ToString();
}


リフレクションを使ってプロパティへアクセスする関数の実装例

/// <summary>
/// Entityオブジェクトのプロパティに値をセットします
/// ネストしたプロパティ(例:info.entity.property)にも対応しています
/// </summary>
/// <param name="entity">値をセットするエンティティオブジェクト</param>
/// <param name="nestedPropertyName">値をセットするプロパティを表す文字列</param>
/// <param name="value">セットする値</param>
public static void SetProperty( object entity, string nestedPropertyName, object value ) 
{
    if( Convert.IsDBNull( value ) ) 
    {
        return;
    }

    string[] propertyNames = nestedPropertyName.Split( new char[] { '.' } );
    object currentEntity = entity;
    for( int i=0; i<propertyNames.Length; i++ ) 
    {
        if( i == propertyNames.Length - 1 ) 
        {
            /* ネストしたプロパティの末端プロパティなら、そのオブジェクトに値をセットします */
            string propertyName = propertyNames[i];
            currentEntity.GetType().GetProperty( propertyName ).SetValue( currentEntity, value );
        }
        else {
            /* ネストしたプロパティの末端でなければそのオブジェクトを処理対象のオブジェクトに設定します
             * 例:info.entity.property の entityなら、entityオブジェクトを処理対象のオブジェクトに設定します
             */
            string propertyName = propertyNames[i];
            currentEntity = currentEntity.GetType().GetProperty( propertyName ).GetValue( currentEntity );
        }
    }
}


使用例

DbCommand cmd = conn.CreateCommand();
cmd.CommandText = "select * from sampletable";
DbDataReader reader = cmd.ExecuteReader();

List<ZoneBaseEntity> entityList = new List<ZoneBaseEntity>();
while( reader .Read() )
{
    ZoneBaseEntity entity = new ZoneBaseEntity();
    for( int i = 0; i < reader.FieldCount; i++ )
    {
        string fieldName = ToCamelCase( reader.GetName( i ) );
        object obj = reader.GetFieldValue<object>( i );
        SetProperty( entity, fieldName, obj );
    }
    entityList.Add( entity );
}
cmd.Dispose();
reader.Close();
conn.Close();

return entityList;


参考:Entityのプロパティをキャメルケースでなくパスカルケースにする場合の実装例

/// <summary>
/// スネークケース(_区切りの文字列)をパスカルケースにして返します
/// </summary>
/// <param name="str">変換前の文字列</param>
/// <returns>変換後の文字列</returns>
public static String toPascalCase( string str ) {

    string lowerCase = str.ToLower();
    string[] item = lowerCase.Split( new char[] { '_' } );

    StringBuilder builder = new StringBuilder();
    for( int _i = 0; _i < item.Length; _i++ ) {
        if( item[_i].Contains( '.' ) ) {
            string[] sItem = item[_i].Split( new char[] { '.' } );
            for( int _s = 0; _s < sItem.Length; _s++ ){
                if( 0 < _s ) {
                    builder.Append( "." );
                }
                builder.Append( StringUtils.capitalize( sItem[_s] ) );
            }
        }
        else {
            builder.Append( StringUtils.capitalize( item[_i] ) );
        }
    }

    return builder.ToString();
}