有没有办法找到已删除关系的所有实体?

时间:2011-12-16 20:11:09

标签: c# .net entity-framework entity-framework-4

我试图让我的业务逻辑不知道我的数据层的内部工作方式,反之亦然。

但实体框架正在努力做到这一点。我可以插入一个集合(在我的业务层中),而不需要引用ObjectContext:

order.Containers.Add(new Container { ContainerId = containerId, Order = order });

当需要在数据层中执行SaveChanges()时,这样可以很好地保存。

但是要从集合中删除项目,我需要对ObjectContext的引用。 (我是guide to deleting EF Entities中的情况#1。)如果我这样做:

 delContainers.ForEach(container => order.Containers.Remove(container));

然后当我打电话给SaveChanges()时,我得到一个异常,告诉我我需要删除该对象以及引用。

所以,我的选择是:

  1. 将委托传递给将调用Entity Framework ObjectContext Delete方法的业务逻辑。
  2. 或者(我希望)找到一种方法来获取已删除其引用并实际删除它们的所有实体。(在我的数据层中调用SaveChanges()之前。)< / LI>

    有没有人知道这样做的方法?

    更新:

    我试过了:

    // Add an event when Save Changes is called
    this.ObjectContext.SavingChanges += OnSavingChanges; 
    

    ...

    void OnSavingChanges(object sender, EventArgs e)
    {
       var objectStateEntries = ObjectContext.ObjectStateManager
                                      .GetObjectStateEntries(EntityState.Deleted);
    
       foreach (var objectStateEntry in objectStateEntries)
       {
           if (objectStateEntry.IsRelationship)
           {
                // Find some way to delete the related entity
           }
       }
    }
    

    但即使我删除了某个关系,也没有删除项目为空。

    (我也尝试查看所有项目,我的关系不在那里。显然,我有一些基本的东西,我没有得到关于ObjectStateManager。)

2 个答案:

答案 0 :(得分:4)

EF的正确解决方案是来自链接文章的第3点。这意味着将FK传播到主体实体到依赖实体的PK。这将形成一个名为identifying relation的东西,它会在从父实体中删除依赖实体时自动删除它。

如果您不想更改模型并且仍希望以持久性无知的方式实现该模型,则可能只能用于independent associations。一些初步实现至少适用于我的简单测试解决方案:

public partial class YourObjectContext
{
    public override int SaveChanges(SaveOptions options)
    {
        foreach (ObjectStateEntry relationEntry in ObjectStateManager
                                             .GetObjectStateEntries(EntityState.Deleted)
                                             .Where(e => e.IsRelationship))
        {
            var entry = GetEntityEntryFromRelation(relationEntry, 0);
            // Find representation of the relation 
            IRelatedEnd relatedEnd = entry.RelationshipManager
                                          .GetAllRelatedEnds()
                                          .First(r => r.RelationshipSet == relationEntry.EntitySet);

            RelationshipType relationshipType = relatedEnd.RelationshipSet.ElementType;
            if (!SkipDeletion(relationshipType))
            {
                // Now we know that model is inconsistent and entity on many side must be deleted
                if (!(relatedEnd is EntityReference)) // related end is many side
                {
                    entry = GetEntityEntryFromRelation(relationEntry, 1);
                }

                if (entry.State != EntityState.Deleted)
                {
                    context.DeleteObject(entry.Entity);
                }
            }
        }

        return base.SaveChanges();
    }

    private ObjectStateEntry GetEntityEntryFromRelation(ObjectStateEntry relationEntry, int index)
    {
        var firstKey = (EntityKey) relationEntry.OriginalValues[index];
        ObjectStateEntry entry = ObjectStateManager.GetObjectStateEntry(firstKey);
        return entry;
    }

    private bool SkipDeletion(RelationshipType relationshipType)
    {
        return
            // Many-to-many
            relationshipType.RelationshipEndMembers.All(
                r => r.RelationshipMultiplicity == RelationshipMultiplicity.Many) ||
            // ZeroOrOne-to-many 
            relationshipType.RelationshipEndMembers.Any(
                r => r.RelationshipMultiplicity == RelationshipMultiplicity.ZeroOrOne);
    }
}

要使其正常运行,必须启用实体以进行动态更改跟踪(所有属性必须为虚拟且实体必须代理),或者您必须手动调用DetectChanges

如果是外键关联,情况可能会更糟,因为您在状态管理器中找不到任何已删除的关系。您必须手动跟踪集合或密钥的更改并进行比较以查找差异(我不确定如何以通用方式执行)外键关联IMHO需要识别关系。使用FK属性已经意味着您在模型中包含了额外的持久性依赖性。

答案 1 :(得分:2)

一种方法是在数据层中编写更改处理程序:

    private void ContainersChanged(object sender,
        CollectionChangeEventArgs e)
    {
        // Check for a related reference being removed. 
        if (e.Action == CollectionChangeAction.Remove)
        {
            Context.DeleteObject(e.Element);
        }
    }

您可以在很多地方连接它 - 在您的对象的构造函数或存储库获取或SavingChanges或任何地方:

    entity.Containers.AssociationChanged += new CollectionChangeEventHandler(ContainersChanged);

现在你可以从其他地方删除这个关联,它会&#34;级联&#34;到实体。