0

n 層アーキテクチャを使用する古い asp.net アプリケーションに新しい機能を追加しています。基本的な例は次のように与えることができます

物体

public class Test
{
    public int ID{get;set;}
    public int name{get;set;}
}

データ アクセス層

public static List<Test> GetTests()
{
    List<Test> list = new List<Test>();
    try
    {
        //codes
        SqlDataReader dr  = com.ExecuteReader();
        while(dr.Read())
            list.Add(FillTestRecord(dr))
        //codes
    }
    catch{}
    return list;
}

private static Test FillTestRecord(IDataRecord dr)
{
    Test test = new Test();
    try{test.ID = Convert.ToInt32(dr["ID"]);}
    catch{}
    try{test.Name = Convert.ToInt32(dr["Name"]);}
    catch{}
    return test;
}

開発では、オブジェクト クラスに新しいフィールドを追加する必要があり、再利用性のために、オブジェクトの種類ごとに Fill*Record メソッドを 1 つだけ使用します。このメソッドは、IDataRecord にオブジェクトのすべての列が含まれていない可能性がある他の多くの DAL メソッドから呼び出すことができます。したがって、すべてのプロパティに個別に try-catch ブロックを配置します。これにより、IDataRecord で使用可能なすべての列が適切に解析されます。

私の質問は、それを行うより良い方法はありますか? また、このタイプのアーキテクチャでのベスト プラクティスは何ですか?

アップデート

David LとAnupのコメント/回答を読んだ後、Extension Methodを使用して別の方法を試しました。方法は次のとおりです。

public static bool TryGetOrdinal(this IDataRecord dr, string column, out int ordinal)
{
    try
    {
        ordinal = dr.GetOrdinal(column);
    }
    catch(Exception ex)
    {
        ordinal = -1; //Just setting a value that GetOrdinal doesn't return
        return false;
    }
    return true;
}

したがって、FillTestRecordメソッドは次のようになります

private static Test FillTestRecord(IDataRecord dr)
{
    Test test = new Test();

    int ordinal = default(int);

    if(dr.TryGetOrdinal("ID",out ordinal))
        test.ID = Convert.ToInt32(dr.GetValue(ordinal));
    if(dr.TryGetOrdinal("Name",out ordinal))
        test.Name = Convert.ToString(dr.GetValue(ordinal));

    return test;
}

これに関する提案は大歓迎です。

更新 03-02-2016

デバッグ中に、提供された列名try-catchが. そこで、 の列名を取得してに置き換える新しいメソッドを作成しました。GetOrdinalDataRecordDataReaderGetOrdinalArray.IndexOf

public static bool TryGetOrdinal(this IDataRecord dr, string[] columnNames, string column, out int ordinal)
{
    ordinal = Array.IndexOf(columnNames, column);
    return ordinal >= 0;
}

そして私FillTestRecordは-

private static Test FillTestRecord(IDataRecord dr, string[] columnNames)
{
    Test test = new Test();

    int ordinal = default(int);

    if(dr.TryGetOrdinal(columnNames, "id",out ordinal))
        test.ID = Convert.ToInt32(dr.GetValue(ordinal));
    if(dr.TryGetOrdinal(columnNames, "name",out ordinal))
        test.Name = Convert.ToString(dr.GetValue(ordinal));

    return test;
}

列名は次のように Fill メソッドに渡されます -

using (var dr = com.ExecuteReader())
{
    string[] colNames = dr.GetColumnNames();
    while (dr.Read())
        list.Add(FillTestRecord(dr, colNames));
}

「GetColumnNames」は新しい拡張メソッドです -

public static string[] GetColumnNames(this IDataReader dr)
{
    string[] columnNames = new string[dr.FieldCount];
    for (int i = 0; i < dr.FieldCount; i++)
    {
        columnNames[i] = dr.GetName(i).ToLower();
    }
    return columnNames;
}
4

3 に答える 3

0

次のコードを使用して、さまざまなオブジェクトのプロパティをマップしています。リフレクションを使用してソース オブジェクトとターゲット オブジェクトのプロパティを取得しますが、IDataRecord で動作するように簡単に変更できます。

public static T MapDTO<T>(object dto) where T : new()
{
    T Result = new T();

    if (dto == null)
        return Result;

    dto.GetType().GetProperties().ToList().ForEach(p =>
        {
            PropertyInfo prop = Result.GetType().GetProperty(p.Name);

            if (prop != null && prop.CanWrite)
            {
                try
                {
                    var convertedVal = Convert.ChangeType(p.GetValue(dto, null), prop.PropertyType);
                    prop.SetValue(Result, convertedVal, null);
                }
                catch (Exception ex)
                {
                    try
                    {
                        prop.SetValue(Result, p.GetValue(dto, null), null);
                    }
                    catch (Exception ex1) { }
                }
            }
        });
    return Result;
}

ここで重要なのは、source プロパティと dest プロパティの名前が同じであることです。

于 2013-10-07T11:04:15.923 に答える