-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Setting a Nullable Foreign Key property to Null triggers cascade delete #27174
Comments
This sounds similar to #26968, which is closed as "by design". However, I verified (you can easily do the same with OP sample) that the same happens with NRT disabled, and even explicitly opting for optional relationship builder.HasOne(x => x.HelpCard).WithMany(op => op.Modules).OnDelete(DeleteBehavior.Cascade).HasForeignKey(@"HelpCardId")
.IsRequired(false);
builder.Navigation(x => x.HelpCard)
.IsRequired(false); The behavior is the same - the dependent entity is deleted rather than detached from parent. P.S. Another SO post just asking the same - How to enable optional foreign key with cascade delete? |
I Edited the initial report to note that Nullable Reference Types are set to Disable for the project, according to the documentation, this should maintain the existing behavior. |
@failwyn The behavior prior to 6.0 was a bug--see #25360. This was fixed in 6.0, and the correct behavior (deleting the orphan) is now observed. If you don't want orphan deletion, but still want cascade deletes, then consider changing the delete orphan timing. |
It's not an Orphan, the Module is the Primary Entity, the Help Card is just a property of the Module, why should setting a Nullable Property of a Primary Entity to Null Delete the Primary Entity? |
@failwyn |
But a Module can legitimately exist without a HelpCard, the Module is the Primary Entity and needs to exist whether it's currently in use or not; is there at least a way to disable the Delete Orphan functionality, because this is a huge breaking change that isn't documented based on a ton of searching and views on StackOverflow. |
@failwyn Yes; see the link I posted. You can set the timing to "Never". This will retain cascade deletes (although based on your description of the relationships it seems questionable that you want cascade deletes either) while preventing orphan deletion. |
Can this be added to the Breaking Changes for Entity Framework Core 6.0? Is there a preferred way to configure DeleteOrphansTiming with DbContextOptionsBuilder or in the Context class (It can't be done in the constructor since ChangeTracker is virtual)? Right now the best way I can find to configure it is using OnActivated when registering it with AutoFac. |
Setting 'context.ChangeTracker.DeleteOrphansTiming = CascadeTiming.Never' throws an exception. Nullable Reference Types is Disabled, the Foreign Key property is Guid?, and the Relationship in the configuration has The association between entity types 'HelpCard' and 'Module' 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, configure the relationship to use cascade deletes. |
I will investigate this. |
@ajcvickers Why cascade delete / delete orphans options affect the operation of the dependent entity? This is counterintuitive to everything we know about cascade delete - defines what to do with dependents when deleting the principal. Here we are not deleting the principal. We are updating the dependent. No relational database deletes the record when you update the nullable cascade delete enforced FK to NULL. Also does not match the behavior explained in Optional relationships
This is exactly what one would expect for optional dependent, regardless of the cascade delete option. So not sure what was fixed in 6.0, but the current behavior definitely sounds like bug to me. And the worse is that there is no workaround - the orphan timing option you are suggesting is irrelevant, as we are not trying to reparent the entity, but simply disassociate it from the parent (after all, it is possible to be created without parent and should be able to be updated to have no parent). |
I agree with everything @powermetal63 said. This does seem like a regression. I am using the following workaround. public class User
{
public string Id { get; set; }
public string? DepartmentId { get; set; }
public Department? Department { get; set; }
}
public class Department
{
public string Id { get; set; }
public List<User>? Users { get; set; }
} and in the builder.Entity<User>()
.HasOne(e => e.Department)
.WithMany(e => e.Users)
.IsRequired(false) // This line has no effect
.OnDelete(DeleteBehavior.Cascade); This correctly sets up an optional FK relationship with cascade delete enabled. However, when I set user.Department = null;
_db.Entry(user).State = EntityState.Modified;
await _db.SaveChangesAsync(); At the end of the day, I feel like this behavior is confusing. When an optional foreign key with cascade delete enabled is set to null, the dependant entity state is set to |
@failwyn @m-azyoksul @powermetal63 I've been pondering on this over the weekend, and I think you folks are right. Cascade delete is typically used with required relationships, where a dependent cannot exist in the database without a principal. In this case, delete orphans behavior makes sense. However, if cascade delete is used with optional relationships, then the dependent can still exist without the principal, which means it probably doesn't make sense to delete orphans automatically. In addition, setting orphan timing to Never definitely should not throw when attempting to save a null FK for optional relationships. I will investigate and discuss with the team what we can do here. We can likely revert this particular change in a patch (although that will require Director-level approval, so I can't promise), but we also need to be conscious of making breaking changes here if other behaviors around orphan deletion are changed. |
we also faced this issue. |
… cascade delete is set to null Fixes #27174.
PR #27216 reverts the 6.0 change. We will seek permission to ship this in the 6.0.3 patch; the window for fixes in 6.0.2 has already closed. |
@ajcvickers Any idea on the timeline for 6.0.2 and 6.0.3? I have clients waiting to go live and there are no usable workarounds to make this work while we wait. |
6.0.2 is scheduled for February; 6.0.3 will likely ship in March. Unfortunately, shipping patches requires a considerable amount of testing, validation, and sign-off work which is coordinated centrally, and is a very slow process. We are investigating ways to make this faster for components like Entity Framework, which are not part of the SDK, but this won't happen immediately. @failwyn You should be able to use the workaround outlined by @m-azyoksul in #27174 (comment) |
That's not a feasible workaround for large applications; Were you able to find anything on why setting DeleteOrphansTiming to Never is throwing an exception for optional relationships? |
I'd have to add that code to hundreds of locations, test to be sure it doesn't create any new issues, then remove it all in March and retest everything again. DeleteOrphansTiming Never would have been a great workaround. Thanks for filing #27218 , will that also be addressed in 6.0.3? |
Using Entity Framework Core 6.0.1
The following code should create a Module model with the HelpCard Foreign Key set, then set the Help Card Foreign Key to Null and save the model to the database, but instead the Cascade Delete is being triggered and the record is deleted from the database. This worked fine in Entity Framework Core 5;
Removing
.OnDelete(DeleteBehavior.Cascade)
from either of the Configurations does not affect this behavior; removing it from both of the Configurations makes it behave as expected (but I need the Cascade).Edit: Nullable Reference Types are set to Disable for the project, according to documentation, this should maintain the existing behavior.
Models
Configuration
EF Core version: 6.00 & 6.01
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: .NET 6.0
Operating system: Windows 10
IDE: Visual Studio 2022 17.0.2
The text was updated successfully, but these errors were encountered: