I'm trying to build an EF Entity with Code First, and an EntityTypeConfiguration
using fluent API. creating primary keys is easy but not so with a Unique Constraint. I was seeing old posts that suggested executing native SQL commands for this, but that seem to defeat the purpose. is this possible with EF6?

- 98,240
- 88
- 296
- 433

- 3,177
- 4
- 25
- 40
6 Answers
On EF6.2, you can use HasIndex()
to add indexes for migration through fluent API.
https://github.com/aspnet/EntityFramework6/issues/274
Example
modelBuilder
.Entity<User>()
.HasIndex(u => u.Email)
.IsUnique();
On EF6.1 onwards, you can use IndexAnnotation()
to add indexes for migration in your fluent API.
http://msdn.microsoft.com/en-us/data/jj591617.aspx#PropertyIndex
You must add reference to:
using System.Data.Entity.Infrastructure.Annotations;
Basic Example
Here is a simple usage, adding an index on the User.FirstName
property
modelBuilder
.Entity<User>()
.Property(t => t.FirstName)
.HasColumnAnnotation(IndexAnnotation.AnnotationName, new IndexAnnotation(new IndexAttribute()));
Practical Example:
Here is a more realistic example. It adds a unique index on multiple properties: User.FirstName
and User.LastName
, with an index name "IX_FirstNameLastName"
modelBuilder
.Entity<User>()
.Property(t => t.FirstName)
.IsRequired()
.HasMaxLength(60)
.HasColumnAnnotation(
IndexAnnotation.AnnotationName,
new IndexAnnotation(
new IndexAttribute("IX_FirstNameLastName", 1) { IsUnique = true }));
modelBuilder
.Entity<User>()
.Property(t => t.LastName)
.IsRequired()
.HasMaxLength(60)
.HasColumnAnnotation(
IndexAnnotation.AnnotationName,
new IndexAnnotation(
new IndexAttribute("IX_FirstNameLastName", 2) { IsUnique = true }));
-
4This is required to name column annotation as "Index"! I wrote another name and it didn't work! I spent hours before I try rename it to original "Index" as in your post and understood that this important. :( There must be a constant for it in the framework to not hard code the string. – Alexander Vasilyev Jul 10 '14 at 07:09
-
useful link for the problem! http://stackoverflow.com/questions/18889218/unique-key-constraints-for-multiple-columns-in-entity-framework – Bassam Alugili Jul 15 '14 at 09:23
-
10@AlexanderVasilyev The constant is defined as `IndexAnnotation.AnnotationName` – Nathan Jul 25 '14 at 21:21
-
3@Nathan Thank you! That's it! The example in this post must be corrected using this constant. – Alexander Vasilyev Aug 07 '14 at 13:45
-
It's also pretty easy to create your own extension methods so you can write things like `Property(x => x.FirstName).Unique("IX_FirstName")` or `new[] { Property(x => x.FirstName), Property(x => x.LastName) }.Unique("IX_FirstNameLastName")` – Phil Mar 26 '15 at 16:36
-
2Can't seem to find it in EF7 - DNX – Shimmy Weitzhandler Jul 21 '15 at 02:52
-
Yeah, and how do you add unique constraints on navigation properties? Lets say if one of the `User` properties has a type of `Role`? how do you make a unique constraint off that? – Tanuki Jul 28 '15 at 12:56
-
That's a lot of typing just to an Unique constraint. Jeez – wickd Dec 21 '15 at 11:17
-
2I believe that IsUnique need to be set to true when creating IndexAttribute in the first example. Like this: `new IndexAttribute() { IsUnique = true }`. Otherwise it creates just regular (non-unique) index. – jakubka Feb 05 '16 at 12:50
-
How would you get this to work with nullable fields? – Eitan K Mar 18 '16 at 13:39
-
1I have tried this and can compile however when I run Update-Database, the index is not added. Anyone knows why and how to solve? – bman Aug 02 '16 at 04:11
-
@bman, check your migration scripts. I tried this on a `string` variable not realizing I needed to set a `HasMaxLength` but after I fixed this, running the migration again did not re-scaffold properly. You should have something like this: `AlterColumn("dbo.GiftCards", "CardNumber", c => c.String(nullable: false, maxLength: 50)); CreateIndex("dbo.GiftCards", "CardNumber", unique: true);` – justanotherdev Nov 24 '16 at 22:16
-
@Yorro, my ConsoleApplication needed `using System.ComponentModel.DataAnnotations.Schema;`. I can't run my application right now to see if it's right, but if this is OK, better add it below the other `using` statment for newbies like me ^^' – Henryk Budzinski Mar 07 '18 at 22:05
As an addition to Yorro's answer, it can also be done by using attributes.
Sample for int
type unique key combination:
[Index("IX_UniqueKeyInt", IsUnique = true, Order = 1)]
public int UniqueKeyIntPart1 { get; set; }
[Index("IX_UniqueKeyInt", IsUnique = true, Order = 2)]
public int UniqueKeyIntPart2 { get; set; }
If the data type is string
, then MaxLength
attribute must be added:
[Index("IX_UniqueKeyString", IsUnique = true, Order = 1)]
[MaxLength(50)]
public string UniqueKeyStringPart1 { get; set; }
[Index("IX_UniqueKeyString", IsUnique = true, Order = 2)]
[MaxLength(50)]
public string UniqueKeyStringPart2 { get; set; }
If there is a domain/storage model separation concern, using Metadatatype
attribute/class can be an option: https://msdn.microsoft.com/en-us/library/ff664465%28v=pandp.50%29.aspx?f=255&MSPPError=-2147217396
A quick console app example:
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
namespace EFIndexTest
{
class Program
{
static void Main(string[] args)
{
using (var context = new AppDbContext())
{
var newUser = new User { UniqueKeyIntPart1 = 1, UniqueKeyIntPart2 = 1, UniqueKeyStringPart1 = "A", UniqueKeyStringPart2 = "A" };
context.UserSet.Add(newUser);
context.SaveChanges();
}
}
}
[MetadataType(typeof(UserMetadata))]
public class User
{
public int Id { get; set; }
public int UniqueKeyIntPart1 { get; set; }
public int UniqueKeyIntPart2 { get; set; }
public string UniqueKeyStringPart1 { get; set; }
public string UniqueKeyStringPart2 { get; set; }
}
public class UserMetadata
{
[Index("IX_UniqueKeyInt", IsUnique = true, Order = 1)]
public int UniqueKeyIntPart1 { get; set; }
[Index("IX_UniqueKeyInt", IsUnique = true, Order = 2)]
public int UniqueKeyIntPart2 { get; set; }
[Index("IX_UniqueKeyString", IsUnique = true, Order = 1)]
[MaxLength(50)]
public string UniqueKeyStringPart1 { get; set; }
[Index("IX_UniqueKeyString", IsUnique = true, Order = 2)]
[MaxLength(50)]
public string UniqueKeyStringPart2 { get; set; }
}
public class AppDbContext : DbContext
{
public virtual DbSet<User> UserSet { get; set; }
}
}

- 2,535
- 2
- 20
- 21
-
47Not if you want to keep your domain model completely separate from storage concerns. – Rickard Liljeberg Oct 26 '14 at 20:40
-
4
-
2Be nice if the Index attribute was separated from Entity Framework so I could include it in my Models project. I understand that it is a storage concern, but the main reason I use it is to put unique constraints on things like UserNames and Role Names. – Sam Feb 20 '15 at 02:24
-
2
-
1This must be out of date. It does not work at all. You just get an exception: Column 'FieldName' in table 'dbo.TableName' is of a type that is invalid for use as a key column in an index. – Cheesus Toast Oct 02 '15 at 15:19
-
1You get an exception if you do not set the string length. I have edited the answer. It think it may normally be 70 characters for the whole name but it is whatever you feel like. – Cheesus Toast Oct 02 '15 at 15:42
-
2The code does not work and my edit to fix it got rejected. Is this some kind of joke? – Cheesus Toast Oct 02 '15 at 18:55
-
1@CheesusToast - post your edit as a separate answer then. Point out the differences and the problems it solves. – H H Oct 28 '15 at 08:28
-
4This only works if you also restrict the length of the string, as SQL doesn't allow *nvarchar(max)* to be used as a key. – JMK Sep 17 '16 at 16:54
-
Here is an extension method for setting unique indexes more fluently:
public static class MappingExtensions
{
public static PrimitivePropertyConfiguration IsUnique(this PrimitivePropertyConfiguration configuration)
{
return configuration.HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute { IsUnique = true }));
}
}
Usage:
modelBuilder
.Entity<Person>()
.Property(t => t.Name)
.IsUnique();
Will generate migration such as:
public partial class Add_unique_index : DbMigration
{
public override void Up()
{
CreateIndex("dbo.Person", "Name", unique: true);
}
public override void Down()
{
DropIndex("dbo.Person", new[] { "Name" });
}
}
Src: Creating Unique Index with Entity Framework 6.1 fluent API

- 1
- 1

- 2,393
- 1
- 25
- 34
@coni2k 's answer is correct however you must add [StringLength]
attribute for it to work otherwise you will get an invalid key exception (Example bellow).
[StringLength(65)]
[Index("IX_FirstNameLastName", 1, IsUnique = true)]
public string FirstName { get; set; }
[StringLength(65)]
[Index("IX_FirstNameLastName", 2, IsUnique = true)]
public string LastName { get; set; }

- 2,184
- 3
- 24
- 32
Unfortunately this is not supported in Entity Framework. It was on the roadmap for EF 6, but it got pushed back: Workitem 299: Unique Constraints (Unique Indexes)

- 232,247
- 41
- 429
- 459

- 28,294
- 6
- 61
- 84
modelBuilder.Property(x => x.FirstName).IsUnicode().IsRequired().HasMaxLength(50);

- 1,183
- 14
- 19