question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Uniquify and validate Check Constraint name

See original GitHub issue

HasCheckConstraint has a name parameter that it uses as the name of the constraint in the database.

Constraints are database objects and their names must be unique in the whole database (not just the table they belong to… as I found out the hard way by getting into a conflict 😄), so to mitigate this we should a use naming convention. Right now we have to do this manually and prepend our constraint names with the name of the table like this:

builder.HasCheckConstraint("AspNetUsers_UserName_SameAsEmail", ...);
builder.HasCheckConstraint("AspNetUsers_Created_NotBySelf", ...);
builder.HasCheckConstraint("AspNetUsers_LastLogonAtUtc_LastLogonInfo_BothOrNonePresent", ...);

That’s why I created an extension method that does this for me:

/// <summary>
/// Calls <see cref="RelationalEntityTypeBuilderExtensions.HasCheckConstraint{TEntity}(EntityTypeBuilder{TEntity}, string, string)"/>
/// with the name of the table prepended to <paramref name="name"/> to prevent constraint name conflicts.
/// </summary>
public static EntityTypeBuilder<TEntity> HasLocalCheckConstraint<TEntity>(this EntityTypeBuilder<TEntity> entityTypeBuilder, string name, string sql) where TEntity : class
{
    var tableName = entityTypeBuilder.Metadata.GetTableName();
    return entityTypeBuilder.HasCheckConstraint(FormattableString.Invariant($"CK_{tableName}_{name}"), sql);
}

and also uses the standard CK prefix as a convention. Then I only use HasLocalCheckConstraint to create check constraints and have to be careful to never call HasCheckConstraint directly.

It would be nice if EF Core had this feature builtin or could do this automatically. It would also ensure that all database object created by EF Core follow the naming convention that it uses now, with a two letter prefix for the type of the object (such as PK, AK, FK, IX).

Just changing the existing behavior of HasCheckConstraint would of course be a huge breaking change and adding a parameter to opt-in to this behavior would be clumsy and it should really be the default in my opinion.

I also noticed that while methods like HasDefaultValue, HasDefaultValueSql and HasComputedColumnSql follow the convention where if they take SQL, their names end with Sql, and if there’s an expression-based version, it doesn’t. What if the existing method was deprecated and the new name would be HasCheckConstraintSql with this new naming behavior? If there’s an expression-based version added later (#15409), that would take the name HasCheckConstraint and still follow the new behavior because it would be a separate overload from the deprecated one (or the deprecated one could be gone by that time).

To allow for compatibility with existing constraint names, the new method could take an optional parameter (bool or enum) to disable the name transformation, but it should be on by default in my opinion.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:15 (8 by maintainers)

github_iconTop GitHub Comments

1reaction
ryan-carboncommented, May 12, 2020

If you plan to add an overload to HasCheckConstraint that doesn’t take a name, it would be great if you could also add an overload to HasDefaultValue that does take a name to align the two.

1reaction
ryan-carboncommented, Jan 24, 2020

Type1 needs to have unique name across database. PK on blog table with same name as AK on post table also fails.

In SqlServer, Type1 names need to be unique across a schema not the entire database, the code below runs fine.

create schema a
create schema b

create table a.tableName (columnName int, constraint ConstraintName check (columnName=1))
create table b.tableName (columnName int, constraint ConstraintName check (columnName=1))

Supporting documentation - https://docs.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql

CONSTRAINT Is an optional keyword that indicates the start of the definition of a PRIMARY KEY, NOT NULL, UNIQUE, FOREIGN KEY, or CHECK constraint.

constraint_name Is the name of a constraint. Constraint names must be unique within the schema to which the table belongs.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Unique Name for each UserID constraint in "Check ...
Just create a unique constraint on it. CREATE UNIQUE INDEX uk_settings_userid_name ON Settings (UserID, Name);.
Read more >
Unique Constraints and Check Constraints - SQL Server
UNIQUE constraints and CHECK constraints are two types of constraints that can be used to enforce data integrity in SQL Server tables.
Read more >
How to use SQL Check Constraints
This article will show details about SQL check constraints and the relationship between constraints and query performance.
Read more >
Constraints reference
You must always specify a unique name for the constraint. As such, you cannot normally specify a ... Constraints are checked during the...
Read more >
Commonly used SQL Server Constraints: FOREIGN KEY, ...
The CHECK constraint comes into action to evaluate the inserted or modified values, where the value that satisfies the condition will be ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found