在我的DbContext子类中,我重写了SaveChanges()方法,因此我可以实现一种类似触发器的功能(在实际保存更改之前)。 现在,在其中一些触发器中,有必要检测某些关系是否已经改变,无论多对多,一对一/零等等。
我已经阅读了互联网上的一些帖子,包括本网站上的一些帖子,提到DbContext API没有公开任何获取关系信息的方法。 但是,ObjectContext应该能够。
我的SaveChanges方法:
public override int SaveChanges()
{
IEntity entity;
ChangeTracker.DetectChanges();
var stateManager = ((IObjectContextAdapter)this).ObjectContext.ObjectStateManager;
var added = stateManager.GetObjectStateEntries(EntityState.Added).ToList();
var updated = stateManager.GetObjectStateEntries(EntityState.Modified).ToList();
var deleted = stateManager.GetObjectStateEntries(EntityState.Deleted).ToList();
var unchanged = stateManager.GetObjectStateEntries(EntityState.Unchanged).ToList();
while ((entity = _entitiesRequiringTriggering.FirstOrDefault(x => x.Value).Key) != null)
{
_entitiesRequiringTriggering[entity] = false;
var entry = ChangeTracker.Entries<IEntity>().SingleOrDefault(x => x.State != EntityState.Unchanged && x.Entity == entity);
if (entry == null) continue;
var trigger = Triggers.Triggers.GetTriggerForEntity(entry.Entity, this);
if (trigger == null) continue;
trigger.BeforeSave(entry.Entity);
switch (entry.State)
{
case EntityState.Added:
trigger.BeforeAdd(entry.Entity);
break;
case EntityState.Modified:
trigger.BeforeUpdate(entry.Entity);
break;
case EntityState.Deleted:
trigger.BeforeDelete(entry.Entity);
break;
}
}
return base.SaveChanges();
}
请注意,添加,已更新,已删除和未更改这四个变量。 根据我到目前为止所发现的,GetObjectStateEntries应该返回ObjectStateEntry的集合,它具有IsRelationship属性。
我在测试应用程序中运行以下代码:
using (var db = container.Resolve<IDatabaseContext>())
{
var cus = db.Query<Customer>().Single(x => x.Id == 1);
var newAddress = db.Query<Address>().Single(x => x.Id == 5);
cus.Address = newAddress; //also sets the foreign key property Customer.AddressId to its new corresponding value
db.SaveChanges();
}
当我在调用后检查SaveChanges中的代码时,我得到了预期的结果: 一个结果是更新列表,Customer对象。 但是,我从来没有得到关系(一对一)Customer_Address的ObjectStateEntry。
我需要能够在关系发生变化时如前所述进行检测。 对于正常的标量属性,您可以这样做:
var changed = DbEntry.Property(x => x.Name).OriginalValue == DbEntry.Property(x => x.Name).CurrentValue;
但对于明显不起作用的参考属性。 有什么想法吗?
答案 0 :(得分:11)
您可以使用此ExtensionMethod
来获取已更改的关系列表
public static class DbContextExtensions
{
public static IEnumerable<Tuple<object, object>> GetRelationships(
this DbContext context)
{
return GetAddedRelationships(context)
.Union(GetDeletedRelationships(context));
}
public static IEnumerable<Tuple<object, object>> GetAddedRelationships(
this DbContext context)
{
return GetRelationships(context, EntityState.Added, (e, i) => e.CurrentValues[i]);
}
public static IEnumerable<Tuple<object, object>> GetDeletedRelationships(
this DbContext context)
{
return GetRelationships(context, EntityState.Deleted, (e, i) => e.OriginalValues[i]);
}
private static IEnumerable<Tuple<object, object>> 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 => Tuple.Create(
objectContext.GetObjectByKey((EntityKey)getValue(e, 0)),
objectContext.GetObjectByKey((EntityKey)getValue(e, 1))));
}
}