現在、エンティティフレームワークのChangeTrackerを監査目的で使用しようとしています。私は私のDbContextのSaveChanges()メソッドをオーバーライドし、追加、変更、または削除されたエンティティのログを作成します。ここではそのFWIWためのコードは次のとおりです。動作を伴う多対多リレーションシップのエンティティフレームワークの変更の追跡
public override int SaveChanges()
{
var validStates = new EntityState[] { EntityState.Added, EntityState.Modified, EntityState.Deleted };
var entities = ChangeTracker.Entries().Where(x => x.Entity is BaseEntity && validStates.Contains(x.State));
var entriesToAudit = new Dictionary<object, EntityState>();
foreach (var entity in entities)
{
entriesToAudit.Add(entity.Entity, entity.State);
}
//Save entries first so the IDs of new records will be populated
var result = base.SaveChanges();
createAuditLogs(entriesToAudit, entityRelationshipsToAudit, changeUserId);
return result;
}
これは「通常」のエンティティのための素晴らしい作品。シンプルな多対多の関係のために、しかし、私は素晴らしいthisで説明したように「独立協会」を含めるには、この実装を拡張しなければならなかったSOので、同様のObjectContextを経由して、変更をアクセスする答え:
private static IEnumerable<EntityRelationship> GetRelationships(this DbContext context, EntityState relationshipState, Func<ObjectStateEntry, int, object> getValue)
{
context.ChangeTracker.DetectChanges();
var objectContext = ((IObjectContextAdapter)context).ObjectContext;
return objectContext
.ObjectStateManager
.GetObjectStateEntries(relationshipState)
.Where(e => e.IsRelationship)
.Select(
e => new EntityRelationship(
e.EntitySet.Name,
objectContext.GetObjectByKey((EntityKey)getValue(e, 0)),
objectContext.GetObjectByKey((EntityKey)getValue(e, 1))));
}
一度実装
、このでも機能しましたが、接合テーブルを使用する多対多リレーションシップの場合にのみ有効でした。これは、関係がクラス/エンティティではなく、各外部キーごとに2つの列を持つデータベーステーブルのみで表される状況を指しています。
ただし、データモデルに多対多リレーションシップがありますが、リレーションシップには「ビヘイビア」(プロパティ)があります。この例では、ProgramGroup
はPin
プロパティを持つ多対多の関係である。このような状況で
public class Program
{
public int ProgramId { get; set; }
public List<ProgramGroup> ProgramGroups { get; set; }
}
public class Group
{
public int GroupId { get; set; }
public IList<ProgramGroup> ProgramGroups { get; set; }
}
public class ProgramGroup
{
public int ProgramGroupId { get; set; }
public int ProgramId { get; set; }
public int GroupId { get; set; }
public string Pin { get; set; }
}
、私はProgramGroup
への変更を見ていないよに(例えばピンが変更された場合。) 「通常の」DbContext ChangeTrackerも、ObjectContext関係メソッドも使用できません。ただし、コードをステップ実行すると、ObjectContextのStateEntriesに変更があることがわかりますが、エントリにはIsRelationship=false
があります。もちろん、.Where(e => e.IsRelationship)
の条件は失敗します。
私の質問は、それが実際のクラス/エンティティによって表され、なぜそれがObjectContext StateEntriesの関係としてマークされていないので、通常のDbContext ChangeTrackerに表示されない動作との多対多の関係ですか?また、これらのタイプの変更にアクセスするためのベストプラクティスは何ですか?
ありがとうございます。
EDIT:多分明示ProgramGroup
の設定を定義しない場合、問題の原因であることをFrancescCastellsさんのコメント@に対応して 、私は次のような構成を追加しました:
public class ProgramGroupConfiguration : EntityTypeConfiguration<ProgramGroup>
{
public ProgramGroupConfiguration()
{
ToTable("ProgramGroups");
HasKey(p => p.ProgramGroupId);
Property(p => p.ProgramGroupId).IsRequired();
Property(p => p.ProgramId).IsRequired();
Property(p => p.GroupId).IsRequired();
Property(p => p.Pin).HasMaxLength(50).IsRequired();
}
そしてここでは、私の他の構成があります:
これらが実装されているpublic class ProgramConfiguration : EntityTypeConfiguration<Program>
{
public ProgramConfiguration()
{
ToTable("Programs");
HasKey(p => p.ProgramId);
Property(p => p.ProgramId).IsRequired();
HasMany(p => p.ProgramGroups).WithRequired(p => p.Program).HasForeignKey(p => p.ProgramId);
}
}
public class GroupConfiguration : EntityTypeConfiguration<Group>
{
public GroupConfiguration()
{
ToTable("Groups");
HasKey(p => p.GroupId);
Property(p => p.GroupId).IsRequired();
HasMany(p => p.ProgramGroups).WithRequired(p => p.Group).HasForeignKey(p => p.GroupId);
}
、EFはまだChangeTrackerで修正ProgramGroup
は表示されません。
プログラムグラフのマッピングを含めることはできますか? IsRelationship = falseの場合、おそらくrelantionship設定に何か問題がありますか? –
@FrancescCastells私は実際に私のProgram-ProgramGroup-Group関係のための 'EntityTypeConfiguration'を明示的に定義していません。 EntityFrameworkは慣例によりそれを処理しています。 – im1dermike
OK。それが正しくマップされていない限り、明示的にマップすることをお勧めします。たとえば、ナビゲーションプロパティのないGroupとの関係について実際に知っていますか? –