简体   繁体   中英

Entity Framework: How do I delete table rows that reference each other?

How do I delete the order without getting this exception?

UserLicenses references SerialOnOrderDetails and vice-versa:

The DELETE statement conflicted with the REFERENCE constraint "FK_SerialsOnOrderDetail_UserLicenses". The conflict occurred in database "sales", table "dbo.SerialsOnOrderDetail", column 'UserLicenseId'.

Delete confirmed controller action code:

[Authorize(Roles = "admin")]    
[HttpPost, ActionName("Delete")]
public async Task<ActionResult> DeleteConfirmed(int id)
{
    Order order = GetOrderById(id);

    if (order.UserLicenses.Count > 0)
    {
        context.UserLicenses.RemoveRange(order.UserLicenses);
    }

    if (order.SerialsOnOrderDetails.Count > 0)
    {
        context.SerialsOnOrderDetails.RemoveRange(order.SerialsOnOrderDetails);
    }

    context.Orders.Remove(order);

    context.SaveChanges(); // Exception here !!!
}

Additional classes:

public partial class UserLicense
{   
    public string Id { get; set; }
    public int OrderId { get; set; }
    public string ProductId { get; set; }
    public int CustomerId { get; set; }
    public string AssignedUserId { get; set; }
    public bool IsActive { get; set; }

    public virtual AspNetUser AspNetUser { get; set; }
    public virtual Customer Customer { get; set; }
    public virtual Order Order { get; set; }
    public virtual Product Product { get; set; }

    public virtual ICollection<SerialsOnOrderDetail> SerialsOnOrderDetails { get; set; }
}

public partial class SerialsOnOrderDetail
{
   public int orderID { get; set; }
   public string serial { get; set; }
   public string productID { get; set; }
   public string UserLicenseId { get; set; }
   public int customerID { get; set; }

   public virtual Product Product { get; set; }
   public virtual Serial Serial1 { get; set; }
   public virtual Order Order { get; set; }
   public virtual UserLicense UserLicense { get; set; }
   public virtual Customer Customer { get; set; }
}

public partial class Order
{
    public Order()
    {
        this.OrderDetails = new HashSet<OrderDetail>();
        this.SerialsOnOrderDetails = new HashSet<SerialsOnOrderDetail>();
        this.UserLicenses = new HashSet<UserLicense>();
    }

    public int orderID { get; set; }
    public int customerID { get; set; }
    public string promoCodeID { get; set; }
    public System.DateTime date { get; set; }
    public Nullable<int> resellerID { get; set; }
    public string invoiceID { get; set; }
    public string poNumber { get; set; }
    public Nullable<System.DateTime> paymentDate { get; set; }
    public Nullable<bool> validated { get; set; }
    public string resellerOrderID { get; set; }
    public Nullable<int> parentOrderID { get; set; }
    public int months { get; set; }

    public virtual Customer Customer { get; set; }
    public virtual ICollection<OrderDetail> OrderDetails { get; set; }
    public virtual PromoCode PromoCode { get; set; }
    public virtual Reseller Reseller { get; set; }
    public virtual ICollection<SerialsOnOrderDetail> SerialsOnOrderDetails { get; set; }
    public virtual Order ParentOrder { get; set; }
    public virtual ICollection<UserLicense> UserLicenses { get; set; }
}

Did you verify if UserLicenses and SerialsOnOrderDetails collections are properly loaded and not empty? Are you sure removerange is the proper way to do it? I suggest you to read a few tutorials about EF if you are not used to it.

Maybe you'll have to update GetOrderById with.Include("....") directives to load these collections, or load the related items manually.

That constraint message you quote is from the underlying SQL Server. It's not an EF error as such, it's passed through.

When I get this sort of problem in TSQL the solution is generally to delete both of the mutually referencing rows in a single transaction.

While I'm not terribly familiar with EF, a quick search turn up this example of putting multiple operations into a single transactional context instead of the default behaviour of a single transaction per operation.

{
    context.Database.Log = Console.WriteLine;
    using (DbContextTransaction transaction = context.Database.BeginTransaction())
    {
        try
        {
            Author author1 = new Author() {    Name = "Mark" };
            Author author2 = new Author() {    Name = "John" };
            
            context.Authors.Add(author1);
            context.SaveChanges();
            
            context.Authors.Add(author2);
            context.SaveChanges();
            transaction.Commit();
        }
        catch (Exception ex)
        {
            transaction.Rollback();
        }
    }
}

I notice another respondent describes other things that could be wrong. It is entirely possible that we are both right and there are multiple issues to resolve.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM