11

私のデータベースには、変更を加えたアプリケーションからログインしたユーザーを収集する予定のすべてのテーブルに「LastModifiedUser」列があります。データベース ユーザーについて話しているわけではないので、基本的にこれは各エンティティの単なる文字列です。他の開発者がエンティティをインスタンス化するたびに割り当てることを覚えておく必要がないように、エンティティごとにこれをデフォルトにする方法を見つけたいと思います。

したがって、次のようなことが起こります。

using (EntityContext ctx = new EntityContext())
{
    MyEntity foo = new MyEntity();

    // Trying to avoid having the following line every time
    // a new entity is created/added.
    foo.LastModifiedUser = Lookupuser(); 

    ctx.Foos.Addobject(foo);
    ctx.SaveChanges();
}
4

2 に答える 2

25

EF 4.0 では、ObjectStateManager

を利用してこれを実現する完璧な方法があり ます。まず、ObjectContext の部分クラスを作成し、 ObjectContext.SavingChanges Eventをサブスクライブする必要があります。このイベントをサブスクライブする最適な場所は、OnContextCreated メソッド内です。このメソッドは、コンテキスト オブジェクトのコンストラクターと、実装のない部分メソッドであるコンストラクター オーバーロードによって呼び出されます。

partial void OnContextCreated() {
    this.SavingChanges += Context_SavingChanges;
}


ジョブを実行する実際のコードは次のとおりです。

void Context_SavingChanges(object sender, EventArgs e) {

    IEnumerable<ObjectStateEntry> objectStateEntries = 
        from ose 
        in this.ObjectStateManager.GetObjectStateEntries(EntityState.Added 
                                                         | EntityState.Modified)
        where ose.Entity != null
        select ose;

    foreach (ObjectStateEntry entry in objectStateEntries) {

        ReadOnlyCollection<FieldMetadata> fieldsMetaData = entry.CurrentValues
                .DataRecordInfo.FieldMetadata;

        FieldMetadata modifiedField = fieldsMetaData
            .Where(f => f.FieldType.Name == "LastModifiedUser").FirstOrDefault();

        if (modifiedField.FieldType != null) {

            string fieldTypeName = modifiedField.FieldType.TypeUsage.EdmType.Name;                    
            if (fieldTypeName == PrimitiveTypeKind.String.ToString()) {
                entry.CurrentValues.SetString(modifiedField.Ordinal, Lookupuser());
            }
        }
    }
}

コードの説明:
このコードは、 LastModifiedUserプロパティを持つ追加または変更されたエントリを見つけ、そのプロパティをカスタムLookupuser()メソッドからの値で更新します。 foreach ブロックでは、クエリは基本的に各エントリのCurrentValuesにドリルダウンします。次に、Whereメソッドを使用して、そのエントリの各FieldMetaDataアイテムの名前を調べ、 NameLastModifiedUserであるアイテムのみを選択します。次に、if ステートメントは、LastModifiedUserプロパティが文字列であることを確認します。

分野; 次に、フィールドの値を更新します。

このメソッドを接続する別の方法 ( SavingChangesイベントをサブスクライブする代わりに) は、 ObjectContext.SaveChanges Methodをオーバーライドすることです。

ところで、上記のコードは、プログラミング エンティティ フレームワークの本に掲載されているジュリー ラーマンのものです。 セルフ トラッキング POCO 実装の編集: セルフ トラッキング POCO がある場合、最初に T4 テンプレートを変更して OnContextCreated() メソッドを呼び出すようにします。ObjectContext.tt ファイルを見ると、Initialize()があります。




すべてのコンストラクターによって呼び出されるメソッドであるため、OnContextCreated() メソッドを呼び出すのに適しているため、次のように ObjectContext.tt ファイルを変更するだけで済みます。

private void Initialize()
{
    // Creating proxies requires the use of the ProxyDataContractResolver and
    // may allow lazy loading which can expand the loaded graph during serialization.
    ContextOptions.ProxyCreationEnabled = false;
    ObjectMaterialized += new ObjectMaterializedEventHandler(HandleObjectMaterialized);
    // We call our custom method here:
    OnContextCreated();
}

これにより、コンテキストの作成時に OnContextCreated() が呼び出されます。

ここで、POCO をサービス境界の背後に配置すると、ModifiedUserNameには WCF サービス コンシューマーからの残りのデータが含まれている必要があることを意味します。この LastModifiedUserプロパティを公開して更新するか、別のプロパティに格納されていてそのプロパティからLastModifiedUserを更新する場合は、次のように 2 番目のコードを変更できます。


foreach (ObjectStateEntry entry in objectStateEntries) {

    ReadOnlyCollection fieldsMetaData = entry.CurrentValues
            .DataRecordInfo.FieldMetadata;

    FieldMetadata sourceField = fieldsMetaData
            .Where(f => f.FieldType.Name == "YourPropertyName").FirstOrDefault();             

    FieldMetadata modifiedField = fieldsMetaData
        .Where(f => f.FieldType.Name == "LastModifiedUser").FirstOrDefault();

    if (modifiedField.FieldType != null) {

        string fieldTypeName = modifiedField.FieldType.TypeUsage.EdmType.Name;
        if (fieldTypeName == PrimitiveTypeKind.String.ToString()) {
            entry.CurrentValues.SetString(modifiedField.Ordinal,
                    entry.CurrentValues[sourceField.Ordinal].ToString());
        }
    }
}


お役に立てれば。

于 2010-09-27T23:54:54.170 に答える
2

これには現在、nuget パッケージがあります: https://www.nuget.org/packages/TrackerEnabledDbContext

Github : https://github.com/bilal-fazlani/tracker-enabled-dbcontext

于 2014-11-02T08:44:40.927 に答える