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中显示修改后的内容.
虽然实体关系建模理论中提到了“与属性的关系”的概念,但就实体框架而言,您的ProgramGroup
类就是一个实体。x.Entity is BaseEntity
您可能无意中通过检查第一个代码片段将其过滤掉。