【问题标题】:Deleting multiple records for a related table删除相关表的多条记录
【发布时间】:2011-04-11 13:36:34
【问题描述】:

我的数据库中有这两个表,名为 Vendors 和 VendorPriceBreaks:

Vendors
-----------------
VendorID (PK)
Name

VendorPriceBreaks
-----------------
VendorPriceBreakID (PK)
VendorID (FK)
Price

当我删除一个供应商时,我想同时删除与之相关的所有 VendorPriceBreaks。我正在使用实体框架。

我先尝试了这个:

public RedirectToRouteResult Delete(int id)
{
    MyEntities entities = new MyEntities();

    var vendor = entities.Vendors.FirstOrDefault(v => v.VendorID == id);
    entities.Vendors.Context.DeleteObject(vendor);
    entities.Vendors.Context.SaveChanges();

    return RedirectToAction("Index");
}

这给了我错误消息:DELETE 语句与 REFERENCE 约束“FK_VendorPriceBreaks_Vendors”冲突

然后我在删除对象之前添加了这一行:vendor.VendorPriceBreaks.Clear();

但后来我收到了以下错误消息:操作失败:无法更改关系,因为一个或多个外键属性不可为空。当对关系进行更改时,相关的外键属性将设置为空值。如果外键不支持空值,则必须定义新关系,必须为外键属性分配另一个非空值,或者必须删除不相关的对象。

最好的方法是什么?

【问题讨论】:

    标签: c# asp.net asp.net-mvc entity-framework


    【解决方案1】:

    您可以“包含”您的子实体。

    var vendor = entities.Vendors
                         .Include("VendorPriceBreaks")
                         .FirstOrDefault(v => v.VendorID == id);
    

    或者,您可以在 .edmx 设计器中修改 2 个实体之间关系的属性。

    【讨论】:

      【解决方案2】:

      我认为你应该创建一个procedor:

      Create proc DeleteRecords
      @VendorID int       
      As
      BEGIN TRY
          BEGIN TRAN
                 DELETE FROM VendorPriceBreaks
              WHERE VendorID =@VendorID
              DELETE FROM Vendors
              WHERE VendorID =@VendorID        
          COMMIT TRAN
      END TRY
      BEGIN CATCH
        ROLLBACK TRAN
      END CATCH
      

      之后,您可以将此 proc 作为函数添加到您的 entityFramwork 中。

      快乐编码

      【讨论】:

      • 删除的顺序应该颠倒。您必须先删除依赖记录,然后才能删除父记录。
      • uppss :) 我知道,很抱歉
      【解决方案3】:

      如果您没有在数据库中启用级联删除(我认为这将是您模型中的最佳选择;请参阅 p.campbell 的回答),您必须明确删除集合中的项目:

      public RedirectToRouteResult Delete(int id)
      {
          MyEntities entities = new MyEntities();
      
          var vendor = entities.Vendors.FirstOrDefault(v => v.VendorID == id);
          foreach (var item in vendor.VendorPriceBreaks.ToList())
              entities.VendorPriceBreaks.Context.DeleteObject(item);
          entities.Vendors.Context.DeleteObject(vendor);
          entities.Vendors.Context.SaveChanges();
      
          return RedirectToAction("Index");
      }
      

      【讨论】:

        【解决方案4】:

        其他人已经提供了有价值的答案,因此您应该从中选择一个作为接受的答案。

        我只是将其添加为答案,因为它太长了无法评论。通常有四种方法可以实现:

        @p.campbell 所描述的级联删除。重要的是在数据库中的关系上定义 ON CASCADE DELETE 以及在 EF 设计器中的关系上定义 CascadeHere 是必须在两边都设置选项的原因。

        @Bilgehan 描述的存储过程。以防存储过程在父级之前删除子级。你其实可以通过ExecuteStoreCommand直接执行SQL。

        Identifying relation - 这是 EF 中最奇怪的架构决策之一。它要求子实体具有从其唯一 Id 和 FK 到父实体的复合键。如果发生这种情况,您可以简单地调用vendor.VendorPriceBreaks.Clear(),它不仅会删除关系,还会删除子项。缺点是相关对象必须从数据库中加载。

        如@Slauma 所述,手动删除相关对象。如果你没有级联删除、存储过程或识别关系没有别的办法,那就加载相关的对象,然后一一删除。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-01-01
          • 1970-01-01
          • 2013-01-30
          • 2010-12-27
          • 1970-01-01
          相关资源
          最近更新 更多