Efcore: Severed association exception on UPDATE - affected by DeleteBehavior.Restrict

Created on 13 Feb 2018  路  5Comments  路  Source: dotnet/efcore

Hello,

I have the following one-to-many relationship:

```c#
entity
.ToTable("OrderItem");
entity
.HasOne()
.WithMany(oi => oi.OrderItems)
.HasForeignKey(oi => oi.OrderId)
.IsRequired()
.OnDelete(DeleteBehavior.Restrict);

public class Order
{
public int OrderId { get; set; }
...
public ICollection OrderItems { get; set; }
}

public class OrderItem
{
public int OrderItemId { get; set; }
...
public int OrderId { get; set; }
}

public void UpdateOrder(int id, DomainModels.EditOrderModel editOrderModel)
{
var order = GetSingleOrder(id);
var orderItems = _mapper.Map>(editOrderModel.OrderItems);
order.OrderItems = orderItems;
_orderRepository.Save();
}

private DataModels.Order GetSingleOrder(int id)
{
var query = _orderRepository.Filter(
0,
0,
null,
o => o.OrderId == id);
return query
.Include(o => o.OrderItems)
.ThenInclude(oi => oi.Offer)
.Include(o => o.Registration)
.ThenInclude(r => r.Guest)
.Include(o => o.RoomRegistration)
.ThenInclude(rr => rr.Room)
.SingleOrDefault();
}


When I am trying to update a tracked order (with OrderItems included) with NEW collection I am getting the following exception:

Microsoft.EntityFrameworkCore.Update[10000]
An exception occurred in the database while saving changes for context type 'HotelManager.Data.HotelManagerContext'.
System.InvalidOperationException: The association between entity types 'Order' and 'OrderItem' has been severed but the foreign key for this relationship cannot be set to null. If the dependent entity should be deleted, then setup the relationship to use cascade deletes.
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.HandleConceptualNulls()
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.GetEntriesToSave()
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(Boolean acceptAllChangesOnSuccess)
at Microsoft.EntityFrameworkCore.DbContext.SaveChanges(Boolean acceptAllChangesOnSuccess)
System.InvalidOperationException: The association between entity types 'Order' and 'OrderItem' has been severed but the foreign key for this relationship cannot be set to null. If the dependent entity should be deleted, then setup the relationship to use cascade deletes.
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.HandleConceptualNulls()
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.GetEntriesToSave()
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(Boolean acceptAllChangesOnSuccess)
at Microsoft.EntityFrameworkCore.DbContext.SaveChanges(Boolean acceptAllChangesOnSuccess)
fail: Microsoft.AspNetCore.Server.Kestrel[13]
```

The problem does not occur when I am changing the DeleteBehavior to Cascade. I would like to understand how is it that the delete behavior affects an update operation. Since OrderItems were being loaded, shouldn't EF automatically delete old OrderItems before inserting a new collection?

Further technical details

EF Core version: 2.0.1
Database Provider: npgsql
Operating system: macos
IDE: VS Code

closed-question

Most helpful comment

@piotrkolodziej This is what is happening:

  • The Order is queried and the two OrderItems are included into the list on the OrderItems navigation property
  • The OrderItems navigation property is reset to a new list containing one new item
  • EF detects this change--two items have been removed from the relationship, one item has been added
  • Since the relationship is required, meaning the FK is non-nullable, then these OrderItems cannot exist without being associated with an Order--because this would require setting the FK to null
  • Therefore, they can be associated with another Order, or they can be deleted
  • EF normally does this delete using the DeleteBehavior.Cascade, which is the default for required relationships.
  • However, changing the DeleteBehavior tells EF to not delete the entities in this case, but instead detect this situation as, essentially, a constraint violation and throw.

All 5 comments

@piotrkolodziej Can you please post a runnable project/solution or complete code listing that will let us reproduce the behavior you are seeing?

@ajcvickers here is a simple console app that isolates the issue. I've uploaded the ZIP archive to my google drive, I hope this will do. Also, to anyone who will have questions regarding this issue, I will be happy to help.

@piotrkolodziej This is what is happening:

  • The Order is queried and the two OrderItems are included into the list on the OrderItems navigation property
  • The OrderItems navigation property is reset to a new list containing one new item
  • EF detects this change--two items have been removed from the relationship, one item has been added
  • Since the relationship is required, meaning the FK is non-nullable, then these OrderItems cannot exist without being associated with an Order--because this would require setting the FK to null
  • Therefore, they can be associated with another Order, or they can be deleted
  • EF normally does this delete using the DeleteBehavior.Cascade, which is the default for required relationships.
  • However, changing the DeleteBehavior tells EF to not delete the entities in this case, but instead detect this situation as, essentially, a constraint violation and throw.

@ajcvickers but when i load one object with related(many side) object with simple change same as change modifiedDate, then try to update.
i do not change any of related objects.
for example :
T exist = await context.Set<T>().FindAsync(key); exist.ModifiedDate = DateTime.Now; await context.SaveChangesAsync(); return exist;
but i get this error:
The association between entity types 'Contract' and 'Level' has been severed but the relationship is either marked as 'Required' or is implicitly required because the foreign key is not nullable. If the dependent/child entity should be deleted when a required relationship is severed, then setup the relationship to use cascade deletes

@sajadghobadi Please open a new issue and post a small, runnable project/solution or complete code listing that demonstrates the behavior you are seeing.

Was this page helpful?
0 / 5 - 0 ratings