跟踪实体框架中与行为的多对多关系中的更改

im1*_*ike 22 c# many-to-many entity-framework

我目前正在尝试使用Entity Framework的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;
}
Run Code Online (Sandbox Code Playgroud)

这适用于"普通"实体.但是,对于简单的多对多关系,我必须扩展此实现以包含"独立关联",如此精彩的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))));
}
Run Code Online (Sandbox Code Playgroud)

一旦实现,这也很有效,但仅适用于使用联结表的多对多关系.通过这种方式,我指的是一种情况,其中关系不是由类/实体表示,而是仅包含两列的数据库表 - 每个外键一个.

然而,在我的数据模型中存在某些多对多关系,其中关系具有"行为"(属性).在此示例中,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; }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我没有看到ProgramGroup"正常"DbContext ChangeTracker或ObjectContext关系方法中的a (例如,如果Pin被更改)的更改.但是,当我逐步完成代码时,我可以看到更改位于ObjectContext的StateEntries中,但它的条目IsRelationship=false当然不符合.Where(e => e.IsRelationship)条件.

我的问题是为什么与正常DbContext ChangeTracker中出现的多对多关系没有出现,因为它由实际的类/实体表示,为什么它没有在ObjectContext StateEntries中标记为关系?此外,访问这些类型的更改的最佳做法是什么?

提前致谢.

编辑: 为了回应@FrancescCastells的评论,可能没有明确定义ProgramGroup问题原因的配置,我添加了以下配置:

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();
    }
Run Code Online (Sandbox Code Playgroud)

以下是我的其他配置:

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);
    }
Run Code Online (Sandbox Code Playgroud)

实现这些后,EF仍然不会ProgramGroup在ChangeTracker中显示修改后的内容.

cyn*_*nic 4

虽然实体关系建模理论中提到了“与属性的关系”的概念,但就实体框架而言,您的ProgramGroup类就是一个实体。x.Entity is BaseEntity您可能无意中通过检查第一个代码片段将其过滤掉。