Home > Enterprise >  Using AlternateKey with condition using Code-first approach
Using AlternateKey with condition using Code-first approach

Time:07-21

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);
  • Related