2

データベースからデータを取得した後、次のようにしてDataRow(この場合は DVD)のデータからドメイン オブジェクトを作成していることに気付きました。

DataRow drDvd = myDataTable.Rows[0];
Dvd myDvd = new Dvd();
myDvd.id = drDvd.Field<long>("id");
myDvd.title = drDvd.Field<string>("title");
myDvd.description = drDvd.Field<string>("description");
myDvd.releaseDate = drDvd.Field<DateTime>("releaseDate");

もちろんすぐに感じたように、疑似コードでこれを何度も繰り返しています。

myDvd.field = drDvd.Field<field.type>(field.name);

そして、それをループに入れることができるかどうか疑問に思いましたが、これまでリフレクションを使用したことがありませんでした。私が試したコードは次のとおりです。

Dvd aDvd = new Dvd();
Type t = aDvd.GetType();
FieldInfo[] fields = t.GetFields();
foreach (FieldInfo fi in fields)
{
    fi.SetValue(aDvd, drDvd.Field<fi.FieldType>(fi.Name));
}

問題は、ご存知かもしれませんがField、クラスのメソッドの拡張DataRowが変数を受け入れず、明示的に入力する必要があることです。

私は C# の経験があまりないので、次の 2 つの質問をしたいと思います。

  1. 私がやろうとしていることは良い習慣ですか?
  2. の正しい拡張子を入力するにはどうすればよいField<extension>(name)ですか?
4

4 に答える 4

1

ジェネリック メソッドのメソッド情報を取得し、invoke を呼び出す必要があります。このようにして、ジェネリック型をプログラムで渡すことができます。私は自分の電話を使用していますが、次のように表示されます。

MethodInfo mField = typeof(Dvd).GetMethod("Field");
MethodInfo genericMethod = mField.MakeGenericMethod(new Type[] { fi.FieldType });

GenericMethod.Invoke(aDvd,new Object[]{fi.Name});
于 2012-04-28T13:42:42.190 に答える
1

通常、実際には必要でない場合にリフレクションを使用するのは悪い習慣です。リフレクション メソッドはコンパイル時ではなく実行時にチェックされるため、コンパイラがエラーをチェックできないため、問題のあるコードを追跡するのが難しくなります。

私があなたなら、Entity Framework を見てください。基本的に、データベース データをドメイン オブジェクトにマッピングしているからです。http://msdn.microsoft.com/en-us/library/aa697427%28v=vs.80%29.aspx

于 2012-04-28T13:59:06.783 に答える
0

これは、ドメイン オブジェクトを構築して設定する方法の 1 つです。

    DataRow drDvd = new DataRow();
    Dvd aDvd = new Dvd();
    Type type = typeof(Dvd);
    foreach (FieldInfo fi in type.GetFields())
    {
        fi.SetValue(aDvd, drDvd[fi.Name]);
    } 

DataRow.Field を使用するというあなたのアプローチは、回り道かもしれません。あなたの場合、それは適用されません。

または、アプリケーションでエンティティ フレームワーク (NHibernate、Microsoft EF など) のいずれかを使用することを検討できます。

于 2012-04-28T14:00:15.530 に答える
0

カスタム属性を作成します。属性を実行する際に、フィールド名がデータベースと同じであることに固執しています。現在、これを現在のアプリケーションで使用していますが、うまく機能します。これは Entity SQL に非常に似ています。

public class SqlMetaAttribute : Attribute
{
    public string ColumnName { get; set; }
}

次に、このようなクラスがあります

public class Person
{
    [SqlMeta(ColumnName = "First_Name")]
    publice string FirstName { get; set; }

    [SqlMeta(ColumnName = "Last_Name")]
    publice string LastName { get; set; }
}

次に、同じ種類の関数を持つヘルパー クラスを作成します。この場合、外部の呼び出し元がデータテーブルをループしていると想定しています。テンプレート T を使用して汎用化すると、これが本当に再利用可能になります。「DVD」タイプの実装をして、別のものにコピーして貼り付けるだけではありません。

public static T CreateObjectFromRow<T>(DataRow row)
{
    var newObject = new T();

    if (row != null) SetAllProperties(row, newObject);

    return newObject;
}

public static void SetAllProperties<T>(DataRow row, T newObject)
{
    var properties = typeof(T).GetProperties();

    foreach(var propertyInfo in properties)
    {
        SetPropertyValue(row, newObject, propertyInfo);
    }
}
public static void SetPropertyValue(DataRow row, T newObject, PropertyInfo propertyInfo)
{
    var columnAttribute = propertyInfo.FindAttribute<SqlMetaAttribute>();

    if (columnAttribute == null) return;

    // If the row type is different than the object type and exception will be thrown, but that is
    // okay because if that happens you have to fix your object you are using, or might need some
    // more custom code to help you with that.
    propertyInfo.SetValue(newObject, row.GetValue<object>(columnAttribute.ColumnName), null);
}

// Extension method for row.GetValue<object> used above
public static T GetValue<T>(this DataRow row, string columnName)
{
    if (row.ColumnNameNotFound(columnName) || row.Table.Columns[columnName] == null || row[columnName] is DBNull)
    {
        return default(T);
    }

    return (T)row[columnName];
}
于 2012-04-28T14:09:01.783 に答える