Skip to main content

Adding Unique Constraints with Entity Framework Code First


Entity Framework Code First is a great way to define and maintain your database within your application it self. While it poses a nice set of complementing libraries like Data Annotations and Fluent Configurations which helps you specially in defining phase of your database, it would give you a headache if you try to define a unique constraint on a column. For example in the users table of your application you could probably have an int ID column which would serve as the primary key and you might need to make your Username column a unique one.

Since you are using EF Code First you will soon find out there is no direct way to accomplish this requirement. Unfortunately fluent configurations doesn't have syntax like

HasUnique(u => u.Username);

I asked the same question in stackoverflow, but didn't get a convincing answer. Since there is no direct support from EF for this you could take one of following alternatives to achieve it.

Approach 1 : 
You can code it right inside your business logic. When you are trying to save a user from your application you can have an additional validation logic which checks if there are any users in the database with same username, needless to say that this is really a manual approach and you will have to implement this each and every place you want to validate a unique constraint which will be cumbersome.

Approach 2 :
You can use a migration and run a plain SQL command using the Sql() method to add the unique constraint.
This will be an ideal solution if you have a guarantee that you do not change the database behind and it will surely lock you to the database you are currently using. Because the plain SQL statement you write here will be a vendor specific one. Following example is written for SQL Server.
namespace EFSample.Migrations
{
    using System;
    using System.Data.Entity.Migrations;
    
    public partial class AddUniqueToUsernameInUsers : DbMigration
    {
        public override void Up()
        {
            Sql("ALTER TABLE dbo.Users ADD CONSTRAINT UC_Username UNIQUE (Username)");
        }
        
        public override void Down()
        {
            Sql("ALTER TABLE dbo.Users DROP CONSTRAINT UC_Username");
        }
    }
}

Given that you do not ever change the database vendor this is a pretty clean solution.
And if you dig further in to what's actually happening inside you could see, that it adds a unique index on username and nothing else, our third approach relies on this fact.


Approach 3 :
Here we will use a migration and add the index directly with C# code without using the native SQL syntax. Since we are using methods provided by the Entity Framework we could hope that it would run on databases from different vendors.

namespace EFSample.Migrations
{
    using System;
    using System.Data.Entity.Migrations;
    
    public partial class AddUniqueIndexToUsernameInUsers : DbMigration
    {
        public override void Up()
        {
            CreateIndex("dbo.Users","Username",true);
        }
        
        public override void Down()
        {
            DropIndex("dbo.Users", "Username");
        }
    }
}
By using the above migration we could achieve the same results as Approach 2, without any vendor specific SQL statements, so I would prefer the third approach over other two since it is the more durable solution.

Comments

  1. Yes the third solution is the best so far. It will be very nice if we get something better in next versions of EF and I mean some vector of extensibility that enables us to fiddle with the migrations in more organized manner like binding our customizations directly with the rest of the fluent code. I actually did something like that, but in the end without internal support it stays in parallel to the standard migrations and is only syntactically better than your approach ...

    ReplyDelete
  2. Yes Michael, we are currently using the third solution. And let's keep an eye on what future EF versions has to offer. In the meantime we all should agree that EF is getting better and better.

    ReplyDelete
  3. Entity Framework 6 will also allow you to do this using annotations:

    modelBuilder.Entity()
    .Property(x => x.YourProperty)
    .HasColumnAnnotation(IndexAnnotation.AnnotationName,
    new IndexAnnotation(new IndexAttribute("UQ_YourProperty") { IsUnique = true }));

    ReplyDelete

Post a Comment

Popular posts from this blog

HTML INPUT enhancement with Regular Expressions and Java Scripts

අද කථා කරන්න යන්නේ බොහොම සරල දෙයක් ගැන. සරල උනාට ඉතින් මට මේක කරගන්න ඕන වෙලා හොයන කොට නම් ඉතින් හොයාගන්න ටිකක් කරදර උනා, ඒ නිසාම තමා මම හිතුවේ මේක ගැන ලියන්න ඕනෙ කියල. අපි හැමෝම HTML forms validate කරන්න Java Script පාවිච්චි කරනවා නේ, එක අලුත් දෙයක් නෙමේ. ඒ වගේම තමා Regular Expressions කියන්නෙත් අපිට අලුත් දෙයක් නෙමේ. අපි බලමු මේ දෙකම පාවිච්චි කරලා HTML textbox එකකට අපිට ඕනෙ characters විතරක් enter කරන්න දෙන්නේ කොහොමද කියල. මෙන්න මේක තමා අපි පාවිච්චි කරන HTML page එක. <!DOCTYPE html> <html> <head> <title>JS and RegEx</title> </head> <body> <label for="txtUsername">Username</lable> <input type="text" id="txtUsername" placeholder="Enter Username"/> </body> </html> මේ තියෙන page එක html විදිහට save කරලා browser එකේ බැලුවම මෙන්න මේ වගේ තමා පෙන්නේ. දැන් හිතන්න අපිට මේ username එකට @,#,%,$ වගේ

Building Highly Scalable Web Applications with Windows Azure

Among many other benefits of moving or building your web applications in cloud, for me I think the most important benefit we get is scalability. When it comes to web applications there are two approaches for scalability. Scale out - This means we increase the number of running instances of the application with a load balancer which distributes the requests among those instances Scale up - This means we increase the physical resources on a single application instance, for example we can increase the RAM of the hosted machine In reality preferred way of web application scalability should be to scale out. Because there are obvious hardware limitations in scale up approach. Bearing that in mind if we look at what Windows Azure provides out of the box, for a certain level it supports scale up approach and it has a great amount of support for scale out approach. Scaling your application out Windows Azure supports both automatic and manual scale out of the application.