gpt4 book ai didi

entity-framework - DbEntityEntry.OriginalValues 不填充复杂属性

转载 作者:行者123 更新时间:2023-12-04 16:55:29 24 4
gpt4 key购买 nike

我正在从网上找到的代码片段中编写审计跟踪。在调用我的 SaveChanges 函数时,我会遍历所有在上下文中注册的修改过的实体,并从它们的更改中构建日志条目。

foreach (DbEntityEntry modifiedEntity in this.ChangeTracker.Entries().Where(p => p.State == System.Data.EntityState.Added || p.State == System.Data.EntityState.Deleted || p.State == System.Data.EntityState.Modified))
{
// For each changed record, get the audit record entries and add them
foreach(AuditLog x in GetAuditRecordsForChange(modifiedEntity, userId))
{
this.AuditLog.Add(x);
}
}

然后,当我尝试访问修改后实体的原始值时,所有标量属性都已填充,但复杂的属性不存在(属性计数将显示为 6 而不是 8)。然后我调用 ToObject()以原始状态构建对象,但显然复杂的属性都是空值。
modifiedEntity.OriginalValues.ToObject()

这只发生在我的一些域对象上,并且这些对象总是在 ToObject() 之后显示为代理。调用而(我不知道为什么)但是那些没有由实体为它们创建的代理,它们的复杂属性填充得很好。当我在整个应用程序中正常使用 POCO 代理时,延迟加载在它们上运行良好。

我注意到,如果我对这些未作为 OriginalValues 数据的一部分填充的复杂属性之一进行更改,则对象的状态不会更改为 Modified,这是有道理的,因为更改跟踪会将原始值与当前值进行比较看看它是否改变了。没有意义的是数据仍然保留在 SaveChanged 上??

编辑:我刚刚注意到,填充其复杂属性的模型对象,有问题的复杂属性(按照惯例)被实体视为“复杂类型”,即没有主键。

有任何想法吗?

最佳答案

要获取实体的所有成员名称,而不仅仅是您可以使用的简单属性 ObjectContext而不是 DbContext然后通过 EntityType 访问成员列表.

((IObjectContextAdapter)this).ObjectContext.ObjectStateManager.GetObjectStateEntry(dbEntry).EntitySet.ElementType.Members

然后您可以使用方法 DbEntityEntry.Member(string propertyName)获取 DbMemberEntry。

Gets an object that represents a member of the entity. The runtime type of the returned object will vary depending on what kind of member is asked for. The currently supported member types and their return types are Reference navigation property (DbReferenceEntry), Collection navigation property (DbCollectionEntry), Primitive/scalar property (DbPropertyEntry) and Complex property (DbComplexPropertyEntry).



下面的代码示例使用它来记录复杂属性的修改。请注意,在记录复杂属性更改时可能需要做一些更性感的事情——我目前正在记录整个复杂属性(序列化为 JSON),而不仅仅是已更改的内部属性,但它完成了工作。
private IEnumerable<AuditLogEntry> GetAuditLogEntries(DbEntityEntry dbEntry)
{
if (dbEntry.State == EntityState.Added)
{
return new AuditLogEntry { ... };
}

if (dbEntry.State == EntityState.Deleted)
{
return new AuditLogEntry { ... };
}

if (dbEntry.State == EntityState.Modified)
{
// Create one AuditLogEntry per updated field.

var list = new List<AuditLogEntry>();

// We need to object state entry to do deeper things.
ObjectStateEntry objectStateEntry = ((IObjectContextAdapter)this).ObjectContext.ObjectStateManager.GetObjectStateEntry(dbEntry);

// Iterate over the members (i.e. properties (including complex properties), references, collections) of the entity type
foreach (EdmMember member in ((IObjectContextAdapter)this).ObjectContext.ObjectStateManager.GetObjectStateEntry(dbEntry).EntitySet.ElementType.Members)
{
var dbMemberEntry = dbEntry.Member(member.Name) as DbPropertyEntry;
if (dbMemberEntry == null || Equals(dbMemberEntry.OriginalValue, dbMemberEntry.CurrentValue))
{
// Member entry isn't a property entry or it isn't modified.
continue;
}

string oldValue;
string newValue;

if (dbMemberEntry is DbComplexPropertyEntry)
{
// Bit a bit lazy here and just serialise the complex property to JSON rather than detect which inner properties have changed.
var complexProperty = (DbComplexPropertyEntry)dbMemberEntry;
oldValue = EntitySerialiser.Serialise(complexProperty.OriginalValue as IAuditableComplexType);
newValue = EntitySerialiser.Serialise(complexProperty.CurrentValue as IAuditableComplexType);
}
else
{
// It's just a plain property, get the old and new values.
var property = dbMemberEntry;
oldValue = property.OriginalValue.ToStringOrNull();
newValue = property.CurrentValue.ToStringOrNull();
}

list.Add(new AuditLogEntry
{
...,
EventType = AuditEventType.Update,
ColumnName = member.Name,
OriginalValue = oldValue,
NewValue = newValue
});
}

return list;
}

// Otherwise empty.
return Enumerable.Empty<AuditLogEntry>();
}

我期待看到其他解决方案。

关于entity-framework - DbEntityEntry.OriginalValues 不填充复杂属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7022721/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com