【发布时间】:2015-11-16 22:22:00
【问题描述】:
我目前正在尝试使用 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;
}
这对“普通”实体非常有效。但是,对于简单的多对多关系,我必须扩展此实现以包括“独立关联”,如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))));
}
实施后,这也很有效,但仅适用于使用联结表的多对多关系。在这里,我指的是关系不是由类/实体表示的情况,而只是一个具有两列的数据库表 - 每个外键一个列。
在我的数据模型中存在某些多对多关系,但是,该关系具有“行为”(属性)。在此示例中,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; }
}
在这种情况下,我在“正常”DbContext ChangeTracker 和 ObjectContext 关系方法中都没有看到 ProgramGroup 的变化(例如,如果 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();
}
这是我的其他配置:
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 可能是关系配置有问题?
-
@FrancescCastells 我实际上并没有为我的 Program-ProgramGroup-Group 关系明确定义
EntityTypeConfiguration。 EntityFramework 按惯例处理它。 -
好的。除非您确定它正确映射它,否则我建议明确映射它,只是为了尝试它。例如,它真的知道与没有导航属性的 Group 的关系吗?
-
@FrancescCastells 我用配置更新了我的帖子。实现之后,EF在ChangeTracker中依然没有更改
ProgramGroup。 -
好的。您提到“独立关联”,根据定义,它们永远不会被标记为已修改,但是使用此映射程序组不是独立关联,因为它们指定了外键,所以这不是原因。恐怕我没有答案。
标签: c# entity-framework many-to-many