I'm trying to implement an AlternateKey constraint on a table. However I was wondering if it was possible to implement a constraint based on a specific condition.
For example, I have table of records:
ID (Primary Key) | Organization ID | Year | IsDeleted |
---|---|---|---|
19b0b3a0-61d8-40b4-9af2-1a48ce18fa56 | 14 | 2022 | False |
9c355c7d-f0fd-4187-8886-8c367ca3852b | 15 | 2022 | False |
db4b8d3c-6cff-4c38-ae03-0baac6277e94 | 16 | 2022 | False |
d1147e62-20c1-4129-aa63-2553b1e205e5 | 17 | 2022 | False |
6c6175bf-6d95-4606-84a3-4f90bb1aa644 | 18 | 2022 | False |
As per my constraint, the alternate key should be a pair of the columns Organization ID and Year. However that should only be enforced if the property "IsDeleted" is False. Meaning I want to be able to have more than one row with the same Organization ID and Year pair with IsDeleted as True.
This is what I'm trying to achieve:
ID (Primary Key) | Organization ID | Year | IsDeleted |
---|---|---|---|
19b0b3a0-61d8-40b4-9af2-1a48ce18fa56 | 14 | 2022 | False |
9c355c7d-f0fd-4187-8886-8c367ca3852b | 15 | 2022 | False |
db4b8d3c-6cff-4c38-ae03-0baac6277e94 | 16 | 2022 | False |
d1147e62-20c1-4129-aa63-2553b1e205e5 | 17 | 2022 | False |
6c6175bf-6d95-4606-84a3-4f90bb1aa644 | 18 | 2022 | True |
607e2465-7a77-4fd4-9b95-29d445ac76c3 | 18 | 2022 | True |
ffe645c3-456f-46f7-b580-2aa7abc3e313 | 18 | 2022 | False |
In EntityFramework I can easily create the constraint like this:
modelBuilder.Entity<Record>().HasAlternateKey(x => new { x.OrganizationId, x.Year });
What would be the next step to implement this logic?
CodePudding user response:
After you've created a unique index (AlternateForeignKey(...)
is short for HasIndex(...).IsUnique
) you can then go ahead and create a foreign key that references it something like this:
modelBuilder.Entity<OtherThing>(entity =>
entity.HasOne(ot => ot.Thing)
.WithMany(t => t.OtherThing)
.HasForeignKey(ot => new {ot.OrganisationId, ot.Year})
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("OtherThing_FK_Thing");
assuming that you've set up a navigation properties OtherThing.Thing
and Thing.OtherThings
.
CodePudding user response:
I found out, that the solution to my problem is not to use the ALTERNATE KEY, but instead the UNIQUE INDEX constraint.
The code-first approach is at this point not necessary for me. If I try to create a new entry in the table in C# that conflicts with the constraint, I will handle it in the code eg. by writing catch (SqlException e)
.
So by executing the following script in SQL I create a conditional constraint for the entities that has IsDeleted set to false, thereby ensuring that only one key pair of OrganizationId and Year can exist that is not deleted:
CREATE UNIQUE INDEX IX_Unique_OrganisationId_Year_Active
ON Records (OrganizationId, Year)
WHERE (IsDeleted = 0);