Efcore: DeleteBehavior.Restrict behaves like ClientSetNull

Created on 17 Nov 2019  路  5Comments  路  Source: dotnet/efcore

DeleteBehavior.Restrict seems to behave exactly like ClientSetNull. Looking at the docs https://docs.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.deletebehavior?view=efcore-3.0, I can't see any difference between Restrict and ClientSetNull. Is there any?

This was very unexpected to me because I expected Restrict to just show a database error if I delete the referenced entity as opposed to EF Core silently setting the foreign key to null. Instead, I spent a lot of time debugging and wondering how the column could have become null. If Restrict behaves like ClientSetNull, is there any option that actually behaves like restrict and opt-out of EF Core interfering with my foreign keys and silently setting them to null?

My scenario for this is:
I have a parent entity and child entities with cascading delete behavior. One of the children is special and is needed almost every time the parent entity is needed, and to simplify a lot of queries, we introduced a foreign key that points from the parent entity to this single child entity. It has to be nullable because it's not possible to create a cyclic dependency with one query (because the entities don't have IDs yet). The DeleteBehavior should be Restrict because deleting this child entity should never delete the parent - deleting the child entity while there's a reference to it from the parent is always a bug in the code (the key needs to be changed to point to a different child entity - it shouldn't ever be null except for the purpose of creating the cyclic dependency). If Restrict didn't have the set null behavior, I could have caught this bug early.

closed-question customer-reported

All 5 comments

@Neme12 Restrict changes what the database does without changing what EF does. ClientNoAction stops EF from nulling an FK property when the principal entity is deleted.

@ajcvickers I would argue that the name is confusing then. Restrict sounds like it should behave like database restrict without any fixup behavior from EF Core.

Restrict changes what the database does

But ClientSetNull sets the database referential action to Restrict as well. So what's the difference between them?

@ajcvickers I think I see your point now. So Restrict changes what the database does (often it doesn't because ReferentialAction.Restrict is the default), but doesn't change what EF Core does, whereas ClientSetNull/ClientNoAction affect what EF Core does without changing what the database does?

This design seems really unfortunate because the enum is not a flags enum which means that I cannot set the database behavior Restrict and EF Core behavior ClientSetNull at the same time. Or is that possible using two OnDelete calls? If that's the case, then that's even more confusing.

Also, I don't see how it would make any sense to set some EF Core fixup behavior (like ClientSetNull or ClientCascade) and a referential action other than Restrict in the database as well. It seems to me that setting Restrict should set the referential action to Restrict and disable any EF Core fixup, whereas ClientSetNull and ClientCascade would also set the referential action to Restrict while enabling appropriate EF Core fixup. Then there would be no need for ClientNoAction. This is what I thought the API was doing.


In any case, the API is really confusing as it is right now.

This change is really confusing, and broke our app while upgrading from 2.1 to 3.1.

Having "Restrict" not actually restricting, but like ClientSetNull is misleading.

I'm not against having an option for that behaviour, but shipping it with the name "Restrict" which used to restrict deletions in earlier versions is just a hidden trap, close to perfidiousness!

Was this page helpful?
0 / 5 - 0 ratings