Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-mvc/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在DbContext中的SaveChanges中向关系(联接表)添加自定义处理?_C#_Asp.net Mvc_Entity Framework_Entity Framework 5 - Fatal编程技术网

C# 如何在DbContext中的SaveChanges中向关系(联接表)添加自定义处理?

C# 如何在DbContext中的SaveChanges中向关系(联接表)添加自定义处理?,c#,asp.net-mvc,entity-framework,entity-framework-5,C#,Asp.net Mvc,Entity Framework,Entity Framework 5,我有一个自定义DbContext,用于记录通过EF对数据库所做的任何更改(插入、更新、删除)。它通过覆盖DbContext上的SaveChanges方法工作。它的工作原理大致如下: public override int SaveChanges() { foreach (DbEntityEntry entry in this.ChangeTracker.Entries()) { Log(entry); } return base.SaveChange

我有一个自定义DbContext,用于记录通过EF对数据库所做的任何更改(插入、更新、删除)。它通过覆盖
DbContext
上的
SaveChanges
方法工作。它的工作原理大致如下:

public override int SaveChanges()
{
    foreach (DbEntityEntry entry in this.ChangeTracker.Entries())
    {
       Log(entry);
    }
    return base.SaveChanges();
}
这对于实体(例如,客户或员工)的变更相当有效。然而,我很难弄清楚如何记录实体之间关系的更改。例如,有一个ClientEmployee联接表,它有一个ClientId和一个EmployeeId。EF正确解释此关系,并在每个表上放置另一个表的
虚拟ICollection
。如何查找在
SaveChanges()
期间添加和删除的关系?我需要能够记录它们(无论它们是添加的还是删除的),即使唯一的区别是在联接表中创建或删除了一行

我一直使用的临时解决方案是,通过添加主键并在代码中手动创建行,将联接表变成实体,但这很麻烦,而且感觉不太对劲。在上面的示例中,员工将拥有一个
虚拟ICollection
,每个
客户员工
实体将拥有一个
客户
和一个
员工
。这就完成了任务,但它增加了开发人员的开销,并增加了所有必须学习和遵循这种非正统模式的开发人员出错的可能性


是否有任何方法可以预览对关系的更改(可能的话,连接表中每个插入或删除的行),即使这些更改严格来说不是对实体的更改?

是的,可以这样做。关键是将
DbContext
转换为其底层
ObjectContext
。对于每个添加的实体,您将只记录添加的相关实体。对于每个
修改的
实体,您需要记录删除的和添加的相关实体

public override int SaveChanges()
{
    foreach (DbEntityEntry entry in this.ChangeTracker.Entries())
    {
       Log(entry);

       switch(entry.State)
       {
          case EntityState.Added:
             Log(GetRelatedEntityKeys(this, entry, EntityState.Added));
             break;

          case EntityState.Modified:
             Log(GetRelatedEntityKeys(this, entry, EntityState.Added));
             Log(GetRelatedEntityKeys(this, entry, EntityState.Deleted));
             break;
       }
    }
    return base.SaveChanges();
}
检查关系的代码为:

private static IList<EntityKey> GetRelatedEntityKeys(DbContext context, DbEntityEntry entry, EntityState entityState)
{
    ObjectContext objectContext = ((IObjectContextAdapter)context).ObjectContext;

    ObjectStateManager objectStateManager = objectContext.ObjectStateManager;

    ObjectStateEntry pivotEntityStateEntry;

    if (!objectStateManager.TryGetObjectStateEntry(entry.Entity, out pivotEntityStateEntry))
    {
        return null;
    }

    EntityKey pivotEntityKey = pivotEntityStateEntry.EntityKey;

    if (entityState == EntityState.Deleted)
    {
        return objectStateManager.GetObjectStateEntries(EntityState.Deleted)
            .Where(e => e.IsRelationship && ((EntityKey)e.OriginalValues[0] == pivotEntityKey || (EntityKey)e.OriginalValues[1] == pivotEntityKey))
            .Select(e => (EntityKey)e.OriginalValues[0] == pivotEntityKey ? (EntityKey)e.OriginalValues[1] : (EntityKey)e.OriginalValues[0])
            .ToList();
    }
    else
    {
        return objectStateManager.GetObjectStateEntries(EntityState.Added)
            .Where(e => e.IsRelationship && ((EntityKey)e.CurrentValues[0] == pivotEntityKey || (EntityKey)e.CurrentValues[1] == pivotEntityKey))
            .Select(e => (EntityKey)e.CurrentValues[0] == pivotEntityKey ? (EntityKey)e.CurrentValues[1] : (EntityKey)e.CurrentValues[0])
            .ToList();
    }
}

您需要为相关实体列表添加日志功能,但似乎您手头有代码的日志部分。

您看过这些文章,但我没有看过,但它们似乎都在做与我基本相同的事情。ChangeTracker公开正在插入、更新或删除的实体,我可以很好地记录这些实体。但是,我不知道如何从变更跟踪器中获取联接表记录。例如,如果我将一名员工与三名客户联系在一起,那么所有4个实体都显示为未更改,因为这些行上的信息都没有更改。然而,我正在向联接表添加4行,将它们链接在一起。这些是我需要记录/审核的行。
private static DbEntityEntry GetRelatedEntityByKey(DbContext context, EntityKey relatedEntityKey)
{
    ObjectContext objectContext = ((IObjectContextAdapter)context).ObjectContext;

    object relatedEntity;
    if (objectContext.TryGetObjectByKey(relatedEntityKey, out relatedEntity))
    {
        return context.Entry(relatedEntity);
    }

    return null;
}