2013-06-06 9 views
6

エンティティに3つのプロパティがあるかどうか確認したいと思います。 CreatedDate、ModifiedDate、およびModifiedByです。汎用エンティティのプロパティを設定するにはどうすればよいですか?

今私は自分のObject ContextのSaveChanges()メソッドで持っているものをハードコーディングしています。

public static bool HasMethod(this object objectToCheck, string methodName) 
{ 
    var type = objectToCheck.GetType(); 
    return type.GetMethod(methodName) != null; 
} 

しかし、どのように、私は直接せずに、これらのプロパティになるだろう:私はそれはオブジェクトがこのようなコードを使用して、特定のメソッドを持っているかどうかを確認することができます知っている

bool newEntity = (entry.State == EntityState.Added); 

if (type == typeof(Foo)) 
{ 
    var r = entry.Entity as Foo; 
    if (r != null) 
    { 
    if (newEntity) 
     r.CreatedDate = DateTime.Now; 
    r.ModifiedDate = DateTime.Now; 
    r.ModifiedBy = HttpContext.Current.User.Identity.Name; 
    } 
} 

:例えば

エンティティをキャストしますか?私はあなたがメソッドの下に使用することができますASP.Net MVC 4

+0

反射を使用します。 'PropertyInfo'です。 – Romoku

+0

おそらく[動的](http://msdn.microsoft.com/en-us/library/dd264736.aspx)がそのために使用できますが、私はそれについてはわかりません。 – dowhilefor

+0

タイトルにタグを追加する意味はありません。詳細については、http://meta.stackexchange.com/q/19190/147072を参照してください。 – Patrick

答えて

12

を使用しています

if (HasMethod(entry.Entity)) 
     entry.Entity.ModifiedDate = DateTime.Now; 

は、どのように私のような何かを行うことができます。存在する場合、プロパティを設定します。呼び出しごとにGetTypeを使用すると、オーバーヘッドが発生する可能性があります。最適化が必要です。

private void TrySetProperty(object obj, string property, object value) { 
     var prop = obj.GetType().GetProperty(property, BindingFlags.Public | BindingFlags.Instance); 
     if(prop != null && prop.CanWrite) 
      prop.SetValue(obj, value, null); 
    } 

使用

TrySetProperty(entry.Entity, "ModifiedDate", DateTime.Now); 
+0

非常に良い。私はそれがどれくらいうまくいくかを見るためにそれをベンチマークします。いずれかの方法で非常に賢い。 – Smith

+1

@Smith:タイプとプロパティの実際のルックアップにはかなりの時間がかかりますが、たとえば静的な辞書にキャッシュすると効率が向上します。 – Patrick

5

次のいずれかを行うことができ、使用リフレクション - すでに何人かの人が言及されています - またはあなたがインターフェイスを作成することができます。自動生成エンティティを使用している場合は、partialというキーワードで定義されているため、同じプロジェクトに別のクラスファイルを作成して同じ名前空間とクラス定義を与えることができます。次に、上に掲示したコードで、オブジェクトがインタフェースを実装しているかどうかを確認し、インタフェースがあればキャストして値を設定します。

インターフェイスの利点は、リフレクション(高価な操作になる可能性があります)を使用していないことです。また、作成する将来のエンティティは、インターフェイスを実装するだけで自動的に動作します。

エンティティプロパティがインターフェイスと正確に一致しない場合は、明示的にインターフェイスを実装できます。これにより、名前の不規則性が処理されます。

例:そのインターフェイスを実装するのは、あなたがインターフェイス、IContainAuditPropertiesを定義したとしましょう、そしてあなたはすべてのあなたの該当するエンティティを持っている、あなたはすべてのあなたの新しい/変更されたエンティティをループしているブロック内で次の操作を実行できます。

var entity = entry.Entity as IContainAuditProperties; 
if(entity != null) 
{ 
    entity.CreatedDate = DateTime.Now; 
    entity.ModifiedDate = DateTime.Now; 
    //etc. 
} 
+0

私はすでにメタデータ属性のために多くのことがあるので、部分クラスを使ってインタフェースを実装するのに問題はありません。私の質問は、直接エンティティを参照せずにキャストする方法です。 – Smith

+0

例を示すために私の答えを更新しました。 –

+1

私はBrianに同意します。インターフェイスは間違いなくここに行く方法です。 –

1

オブジェクトは、このコードを使用して、特定の名前を持つパブリック設定可能なプロパティを持つかどうかをチェックすることができます:それは反射の多くを使用するよう

public static bool HasWritableProperty(this object objectToCheck, string propertyName) 
{ 
    var type = objectToCheck.GetType(); 
    //get a property info for the property, but only if it is a public instance property 
    var pi = type.GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public) 
    //return false if no propery is found 
    if (pi==null) return false; 
    //get the set method for the property 
    var setter = pi.GetSetMethod(); 
    //if it's null the property is not writable 
    return (setter != null); 
} 

しかし、これは非常に効率的なコードは、ありません。

このルートに行くと、このコードの結果をメモするので、すべてのチェックは最大で1回実行されます。

私は自分のプロジェクトで実際に何をしているのですか(私はEFコードファーストを使用しています)、BaseEntityクラスを継承しており、コンクリートエンティティに共通のプロパティを持つクラスがBaseEntityです。これが動作するために、あなたはまた、インタフェース、IBaseEntityを使用することができ、それは同じように機能すること

protected void FillEntityMetadata(BaseEntity entity, bool isUpdate = false) 
{ 
    // Set audit data. 
    if (!isUpdate) 
    { 
    entity.CreatedBy = CurrentUser.ID; 
    entity.CreatedOn = DateTime.Now; 
    entity.IsActive = true; 
    } 
    entity.LastModifiedBy = CurrentUser.ID; 
    entity.LastModifiedOn = DateTime.Now; 
} 

注:その後、私はFillEntityMetadata方法を持っている、それは多かれ少なかれ、このです。

関連する問題