Entity Frameworkを使用しているMVCアプリへの変更履歴/監査ログを作成しています。
具体的には、編集メソッドpublic ActionResult Edit(ViewModel vm)
で、更新しようとしているオブジェクトを見つけ、TryUpdateModel(object)
を使用して、フォームから値を、目的のオブジェクトに転置します。更新。
そのオブジェクトのフィールドが変更されたときに、変更をログに記録したいと思います。したがって、基本的に必要なのは、編集する前にオブジェクトのコピーを作成し、TryUpdateModel(object)
が処理を行った後にオブジェクトを比較することです。つまり.
_[HttpPost]
public ActionResult Edit(ViewModel vm)
{
//Need to take the copy here
var object = EntityFramework.Object.Single(x=>x.ID = vm.ID);
if (ModelState.IsValid)
{
//Form the un edited view model
var uneditedVM = BuildViewModel(vm.ID); //this line seems to confuse the EntityFramework (BuildViewModel() is used to build the model when originally displaying the form)
//Compare with old view model
WriteChanges(uneditedVM, vm);
...
TryUpdateModel(object);
}
...
}
_
しかし、問題は、コードが「未編集のvm」を取得するときです。これにより、EntityFrameworkで予期しない変更が発生するため、TryUpdateModel(object);
がUpdateException
をスローします。
だから質問です-この状況では-EntityFrameworkの外部でobject
のコピーを作成して、変更/監査履歴を比較して、 EntityFrameworkで
編集:トリガーを使用したくない。それをしたユーザー名を記録する必要があります。
edit1:EFv4を使用して、SaveChanges()
をオーバーライドする方法についてはあまりよくわかりませんが、オプションかもしれません
この単純な要件のため、このルートはどこにも行かないようです!ようやく適切にオーバーライドできるようになりましたが、そのコードで例外が発生しました。
_public partial class Entities
{
public override int SaveChanges(SaveOptions options)
{
DetectChanges();
var modifiedEntities = ObjectStateManager.GetObjectStateEntries(EntityState.Modified);
foreach (var entry in modifiedEntities)
{
var modifiedProps = ObjectStateManager.GetObjectStateEntry(entry).GetModifiedProperties(); //This line throws exception The ObjectStateManager does not contain an ObjectStateEntry with a reference to an object of type 'System.Data.Objects.EntityEntry'.
var currentValues = ObjectStateManager.GetObjectStateEntry(entry).CurrentValues;
foreach (var propName in modifiedProps)
{
var newValue = currentValues[propName];
//log changes
}
}
//return base.SaveChanges();
return base.SaveChanges(options);
}
}
_
EF 4を使用している場合は、SavingChanges
イベントにサブスクライブできます。
Entities
は部分クラスであるため、別のファイルに機能を追加できます。したがって、Entities
という名前の新しいファイルを作成し、そこにイベントをフックする部分メソッドOnContextCreated
を実装します
public partial class Entities
{
partial void OnContextCreated()
{
SavingChanges += OnSavingChanges;
}
void OnSavingChanges(object sender, EventArgs e)
{
var modifiedEntities = ObjectStateManager.GetObjectStateEntries(EntityState.Modified);
foreach (var entry in modifiedEntities)
{
var modifiedProps = ObjectStateManager.GetObjectStateEntry(entry.EntityKey).GetModifiedProperties();
var currentValues = ObjectStateManager.GetObjectStateEntry(entry.EntityKey).CurrentValues;
foreach (var propName in modifiedProps)
{
var newValue = currentValues[propName];
//log changes
}
}
}
}
EF 4.1を使用している場合は、 この記事 を介して変更を抽出できます。
FrameLog を参照してください。これは、この目的のために作成したEntity Frameworkロギングライブラリです。商用利用を含むオープンソースです。
これを行う方法を示すコードスニペットを表示する方がよいことはわかっていますが、関係の変更や多対多の変更など、ロギングのすべてのケースを適切に処理するには、コードが非常に大きくなります。ライブラリがあなたのニーズに合っていることを願っていますが、そうでない場合は自由にコードを調整できます。
FrameLogは、すべてのスカラープロパティとナビゲーションプロパティへの変更を記録できます。また、ログに関心のあるサブセットを指定することもできます。
Codeprojectに高い評価の記事があります: Entity Frameworkを使用した監査証跡の実装 。それはあなたが望むことをするようです。プロジェクトでこのソリューションを使用し始めました。最初にデータベースのT-SQLでトリガーを作成しましたが、オブジェクトモデルの変更が常に発生するため、トリガーを維持するのは難しすぎました。