CREATE UNIQUE NONCLUSTERED INDEX [UX_MyEntity_UserId_IsDefault] ON [dbo].[MyEntity]
(
[UserId] ASC,
[IsDefault] ASC
)
WHERE ([IsDefault]=(1))
Because I can only have 1 record with the flag IsDefault set to true, the order of updates is important, I first need to set non default records to false, and then set the default one. Since the EF Core doesn't really know the condition/filter, it doesn't order the updates correclty and I often get an error with the message:
Cannot insert duplicate key row in object 'dbo.MyEntity' with unique index 'UX_MyEntity_UserId_IsDefault'.
Example
In the database I have:
Id
UserId
IsDefault
1
5
0
2
5
1
3
5
0
In the code we have a Parent and a Child object, the Parent has a collection of Children and it goes like this:
var parent = await parentEfRepository.GetByIdAsync(5, cancellationToken);
var newDefaultChild = parent.Children.Where(c => ...);
newDefaultChild.SetAsDefault();
await context.SaveChangesAsync(cancellationToken);
The SetAsDefault() method contains the logic to set other Children as non default and the result is that only 1 Child is marked as being the default one.
When we get to SaveChanges(), EF generates a SQL script that contains the updates which look like this:
SET NOCOUNT ON;
UPDATE [MyEntity] SET [IsDefault] = @p0
OUTPUT INSERTED.[PeriodEnd], INSERTED.[PeriodStart]
WHERE [Id] = @p1;
UPDATE [MyEntity] SET [IsDefault] = @p2
OUTPUT INSERTED.[PeriodEnd], INSERTED.[PeriodStart]
WHERE [Id] = @p3;
Because it's trying to update record with ID 1 first, we would end up with the following:
Id
UserId
IsDefault
1
5
1
2
5
1
3
5
0
And that's when the unique constraint kicks in and throws an error.
I have started experimenting with interceptors but it's getting dirty, surely someone had this issue before me?
Thanks!
Provider and version information
EF Core version: 8.0.11
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: .NET 8.0
Operating system: Windows
IDE: Rider
The question
I have a filtered unique index defined as:
It translates into:
Because I can only have 1 record with the flag
IsDefault
set totrue
, the order of updates is important, I first need to set non default records tofalse
, and then set the default one. Since the EF Core doesn't really know the condition/filter, it doesn't order the updates correclty and I often get an error with the message:Example
In the code we have a
Parent
and aChild
object, theParent
has a collection ofChild
ren and it goes like this:The
SetAsDefault()
method contains the logic to set otherChild
ren as non default and the result is that only 1Child
is marked as being the default one. When we get toSaveChanges()
, EF generates a SQL script that contains the updates which look like this:Because it's trying to update record with ID 1 first, we would end up with the following:
And that's when the unique constraint kicks in and throws an error. I have started experimenting with interceptors but it's getting dirty, surely someone had this issue before me?
Thanks!
Provider and version information
EF Core version: 8.0.11 Database provider:
Microsoft.EntityFrameworkCore.SqlServer
Target framework: .NET 8.0 Operating system: Windows IDE: Rider