Restrição Única no Código do Entity Framework Primeiro

Questão

É possível definir uma restrição exclusiva em uma propriedade usando a syntax fluente ou um atributo? Se não, quais são as soluções alternativas?

Eu tenho uma class de usuário com uma chave primária, mas gostaria de ter certeza de que o endereço de e-mail também é exclusivo. Isso é possível sem editar o database diretamente?

Solução (com base na resposta de Matt)

public class MyContext : DbContext { public DbSet Users { get; set; } public override int SaveChanges() { foreach (var item in ChangeTracker.Entries()) item.Entity.Modified = DateTime.Now; return base.SaveChanges(); } public class Initializer : IDatabaseInitializer { public void InitializeDatabase(MyContext context) { if (context.Database.Exists() && !context.Database.CompatibleWithModel(false)) context.Database.Delete(); if (!context.Database.Exists()) { context.Database.Create(); context.Database.ExecuteSqlCommand("alter table Users add constraint UniqueUserEmail unique (Email)"); } } } } 

Tanto quanto eu posso dizer, não há como fazer isso com o Entity Framework no momento. No entanto, isso não é apenas um problema com restrições exclusivas … você pode criar índices, verificar restrições e possivelmente triggersdores e outras construções também. Aqui está um padrão simples que você pode usar com sua configuração de primeiro código, apesar de admitir que não é agnóstico do database:

 public class MyRepository : DbContext { public DbSet Whatevers { get; set; } public class Initializer : IDatabaseInitializer { public void InitializeDatabase(MyRepository context) { if (!context.Database.Exists() || !context.Database.ModelMatchesDatabase()) { context.Database.DeleteIfExists(); context.Database.Create(); context.ObjectContext.ExecuteStoreCommand("CREATE UNIQUE CONSTRAINT..."); context.ObjectContext.ExecuteStoreCommand("CREATE INDEX..."); context.ObjectContext.ExecuteStoreCommand("ETC..."); } } } } 

Outra opção é se o seu modelo de domínio é o único método de inserir / atualizar dados em seu database, você pode implementar o requisito de exclusividade sozinho e deixar o database fora dele. Esta é uma solução mais portátil e obriga você a ter clareza sobre suas regras de negócios em seu código, mas deixa seu database aberto para dados inválidos sendo restaurados.

Começando com a EF 6.1, agora é possível:

 [Index(IsUnique = true)] public string EmailAddress { get; set; } 

Isso fará com que você obtenha um índice exclusivo em vez de uma restrição exclusiva, estritamente falando. Para fins mais práticos, são os mesmos .

Não é realmente relacionado a isso, mas pode ajudar em alguns casos.

Se você deseja criar um índice composto exclusivo em, digamos, 2 colunas que funcionem como uma restrição para sua tabela, na versão 4.3 você pode usar o novo mecanismo de migrações para alcançá-lo:

Basicamente, você precisa inserir uma chamada assim em um dos seus scripts de migration:

 CreateIndex("TableName", new string[2] { "Column1", "Column2" }, true, "IX_UniqueColumn1AndColumn2"); 

Algo parecido:

 namespace Sample.Migrations { using System; using System.Data.Entity.Migrations; public partial class TableName_SetUniqueCompositeIndex : DbMigration { public override void Up() { CreateIndex("TableName", new[] { "Column1", "Column2" }, true, "IX_UniqueColumn1AndColumn2"); } public override void Down() { DropIndex("TableName", new[] { "Column1", "Column2" }); } } } 

Eu faço um hack completo para obter SQL executado quando o database está sendo criado. Eu crio meu próprio DatabaseInitializer e herdo de um dos inicializadores fornecidos.

 public class MyDatabaseInitializer : RecreateDatabaseIfModelChanges { protected override void Seed(MyDbContext context) { base.Seed(context); context.Database.Connection.StateChange += new StateChangeEventHandler(Connection_StateChange); } void Connection_StateChange(object sender, StateChangeEventArgs e) { DbConnection cnn = sender as DbConnection; if (e.CurrentState == ConnectionState.Open) { // execute SQL to create indexes and such } cnn.StateChange -= Connection_StateChange; } } 

Esse é o único lugar que eu encontrei para colocar em minhas instruções SQL.

Isso é do CTP4. Eu não sei como funciona no CTP5.

Apenas tentando descobrir se havia uma maneira de fazer isso, apenas a maneira que eu encontrei até agora foi impor isso, eu criei um atributo para ser adicionado a cada class onde você fornece o nome dos campos que você precisa para ser único:

  [System.AttributeUsage(System.AttributeTargets.Class, AllowMultiple=false,Inherited=true)] public class UniqueAttribute:System.Attribute { private string[] _atts; public string[] KeyFields { get { return _atts; } } public UniqueAttribute(string keyFields) { this._atts = keyFields.Split(new char[]{','}, StringSplitOptions.RemoveEmptyEntries); } } 

Então na minha aula eu adicionarei:

 [CustomAttributes.Unique("Name")] public class Item: BasePOCO { public string Name{get;set;} [StringLength(250)] public string Description { get; set; } [Required] public String Category { get; set; } [Required] public string UOM { get; set; } [Required] } 

Por fim, adicionarei um método ao meu repository, no método Add ou ao salvar alterações assim:

 private void ValidateDuplicatedKeys(T entity) { var atts = typeof(T).GetCustomAttributes(typeof(UniqueAttribute), true); if (atts == null || atts.Count() < 1) { return; } foreach (var att in atts) { UniqueAttribute uniqueAtt = (UniqueAttribute)att; var newkeyValues = from pi in entity.GetType().GetProperties() join k in uniqueAtt.KeyFields on pi.Name equals k select new { KeyField = k, Value = pi.GetValue(entity, null).ToString() }; foreach (var item in _objectSet) { var keyValues = from pi in item.GetType().GetProperties() join k in uniqueAtt.KeyFields on pi.Name equals k select new { KeyField = k, Value = pi.GetValue(item, null).ToString() }; var exists = keyValues.SequenceEqual(newkeyValues); if (exists) { throw new System.Exception("Duplicated Entry found"); } } } } 

Não é muito legal, pois precisamos confiar na reflection, mas até agora essa é a abordagem que funciona para mim! = D

Também em 6.1 você pode usar a versão da syntax fluente da resposta de @ mihkelmuur da seguinte forma:

 Property(s => s.EmailAddress).HasColumnAnnotation(IndexAnnotation.AnnotationName, new IndexAnnotation( new IndexAttribute("IX_UniqueEmail") { IsUnique = true })); 

O método fluente não é o IMO perfeito, mas pelo menos é possível agora.

Mais detalhes sobre o blog de Arthur Vickers http://blog.oneunicorn.com/2014/02/15/ef-6-1-creating-indexes-with-indexattribute/

Uma maneira fácil em visual basic usando o código EF5 First Migrations

Amostra de class pública

  Public Property SampleId As Integer   Public Property Code() As String 

Classe final

O atributo MaxLength é muito importante para o índice exclusivo do tipo string

Executar cmd: update-database -verbose

após executar cmd: add-migration 1

no arquivo gerado

 Public Partial Class _1 Inherits DbMigration Public Overrides Sub Up() CreateIndex("dbo.Sample", "Code", unique:=True, name:="IX_Sample_Code") End Sub Public Overrides Sub Down() 'DropIndex if you need it End Sub End Class 

Semelhante à resposta de Tobias Schittkowski, mas C # e tem a capacidade de ter vários campos nas restrições.

Para usá-lo, basta colocar um [Único] em qualquer campo que você deseja que seja único. Para strings, você terá que fazer algo como (observe o atributo MaxLength):

 [Unique] [MaxLength(450)] // nvarchar(450) is max allowed to be in a key public string Name { get; set; } 

porque o campo de string padrão é nvarchar (max) e isso não será permitido em uma chave.

Para vários campos na restrição, você pode fazer:

 [Unique(Name="UniqueValuePairConstraint", Position=1)] public int Value1 { get; set; } [Unique(Name="UniqueValuePairConstraint", Position=2)] public int Value2 { get; set; } 

Primeiro, o UniqueAttribute:

 ///  /// The unique attribute. Use to mark a field as unique. The ///  looks for this attribute to /// create unique constraints in tables. ///  internal class UniqueAttribute : Attribute { ///  /// Gets or sets the name of the unique constraint. A name will be /// created for unnamed unique constraints. You must name your /// constraint if you want multiple fields in the constraint. If your /// constraint has only one field, then this property can be ignored. ///  public string Name { get; set; } ///  /// Gets or sets the position of the field in the constraint, lower /// numbers come first. The order is undefined for two fields with /// the same position. The default position is 0. ///  public int Position { get; set; } } 

Em seguida, inclua uma extensão útil para obter o nome da tabela de database de um tipo:

 public static class Extensions { ///  /// Get a table name for a class using a DbContext. ///  ///  /// The context. ///  ///  /// The class to look up the table name for. ///  ///  /// The table name; null on failure; ///  ///  ///  /// Like: ///  /// DbContext context = ...; /// string table = context.GetTableName<Foo>(); ///  ///  ///  /// This code uses ObjectQuery.ToTraceString to generate an SQL /// select statement for an entity, and then extract the table /// name from that statement. ///  ///  public static string GetTableName(this DbContext context, Type type) { return ((IObjectContextAdapter)context) .ObjectContext.GetTableName(type); } ///  /// Get a table name for a class using an ObjectContext. ///  ///  /// The context. ///  ///  /// The class to look up the table name for. ///  ///  /// The table name; null on failure; ///  ///  ///  /// Like: ///  /// ObjectContext context = ...; /// string table = context.GetTableName<Foo>(); ///  ///  ///  /// This code uses ObjectQuery.ToTraceString to generate an SQL /// select statement for an entity, and then extract the table /// name from that statement. ///  ///  public static string GetTableName(this ObjectContext context, Type type) { var genericTypes = new[] { type }; var takesNoParameters = new Type[0]; var noParams = new object[0]; object objectSet = context.GetType() .GetMethod("CreateObjectSet", takesNoParameters) .MakeGenericMethod(genericTypes) .Invoke(context, noParams); var sql = (string)objectSet.GetType() .GetMethod("ToTraceString", takesNoParameters) .Invoke(objectSet, noParams); Match match = Regex.Match(sql, @"FROM\s+(.*)\s+AS", RegexOptions.IgnoreCase); return match.Success ? match.Groups[1].Value : null; } } 

Então, o inicializador do database:

 ///  /// The database initializer. ///  public class DatabaseInitializer : IDatabaseInitializer { ///  /// Initialize the database. ///  ///  /// The context. ///  public void InitializeDatabase(FooContext context) { // if the database has changed, recreate it. if (context.Database.Exists() && !context.Database.CompatibleWithModel(false)) { context.Database.Delete(); } if (!context.Database.Exists()) { context.Database.Create(); // Look for database tables in the context. Tables are of // type DbSet<>. foreach (PropertyInfo contextPropertyInfo in context.GetType().GetProperties()) { var contextPropertyType = contextPropertyInfo.PropertyType; if (contextPropertyType.IsGenericType && contextPropertyType.Name.Equals("DbSet`1")) { Type tableType = contextPropertyType.GetGenericArguments()[0]; var tableName = context.GetTableName(tableType); foreach (var uc in UniqueConstraints(tableType, tableName)) { context.Database.ExecuteSqlCommand(uc); } } } // this is a good place to seed the database context.SaveChanges(); } } ///  /// Get a list of TSQL commands to create unique constraints on the given /// table. Looks through the table for fields with the UniqueAttribute /// and uses those and the table name to build the TSQL strings. ///  ///  /// The class that expresses the database table. ///  ///  /// The table name in the database. ///  ///  /// The list of TSQL statements for altering the table to include unique /// constraints. ///  private static IEnumerable UniqueConstraints( Type tableClass, string tableName) { // the key is the name of the constraint and the value is a list // of (position,field) pairs kept in order of position - the entry // with the lowest position is first. var uniqueConstraints = new Dictionary>>(); foreach (PropertyInfo entityPropertyInfo in tableClass.GetProperties()) { var unique = entityPropertyInfo.GetCustomAttributes(true) .OfType().FirstOrDefault(); if (unique != null) { string fieldName = entityPropertyInfo.Name; // use the name field in the UniqueAttribute or create a // name if none is given string constraintName = unique.Name ?? string.Format( "constraint_{0}_unique_{1}", tableName .Replace("[", string.Empty) .Replace("]", string.Empty) .Replace(".", "_"), fieldName); List> constraintEntry; if (!uniqueConstraints.TryGetValue( constraintName, out constraintEntry)) { uniqueConstraints.Add( constraintName, new List> { new Tuple( unique.Position, fieldName) }); } else { // keep the list of fields in order of position for (int i = 0; ; ++i) { if (i == constraintEntry.Count) { constraintEntry.Add( new Tuple( unique.Position, fieldName)); break; } if (unique.Position < constraintEntry[i].Item1) { constraintEntry.Insert( i, new Tuple( unique.Position, fieldName)); break; } } } } } return uniqueConstraints.Select( uc => string.Format( "ALTER TABLE {0} ADD CONSTRAINT {1} UNIQUE ({2})", tableName, uc.Key, string.Join(",", uc.Value.Select(v => v.Item2)))); } } 

Se você replace o método ValidateEntity em sua class DbContext, também poderá colocar a lógica. A vantagem aqui é que você terá access total a todos os seus DbSets. Aqui está um exemplo:

 using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Data.Entity; using System.Data.Entity.Infrastructure; using System.Data.Entity.ModelConfiguration.Conventions; using System.Data.Entity.Validation; using System.Linq; namespace MvcEfClient.Models { public class Location { [Key] public int LocationId { get; set; } [Required] [StringLength(50)] public string Name { get; set; } } public class CommitteeMeetingContext : DbContext { protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Conventions.Remove(); } protected override DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry, IDictionary items) { List validationErrors = new List(); // Check for duplicate location names if (entityEntry.Entity is Location) { Location location = entityEntry.Entity as Location; // Select the existing location var existingLocation = (from l in Locations where l.Name == location.Name && l.LocationId != location.LocationId select l).FirstOrDefault(); // If there is an existing location, throw an error if (existingLocation != null) { validationErrors.Add(new DbValidationError("Name", "There is already a location with the name '" + location.Name + "'")); return new DbEntityValidationResult(entityEntry, validationErrors); } } return base.ValidateEntity(entityEntry, items); } public DbSet Locations { get; set; } } } 

Eu resolvi o problema por reflection (desculpe, pessoal, VB.Net …)

Primeiro, defina um atributo UniqueAttribute:

  _ Public Class UniqueAttribute Inherits Attribute End Class 

Então, aprimore seu modelo como

  _ Public Class Person  _ Public Property Username() As String End Class 

Finalmente, crie um DatabaseInitializer personalizado (na minha versão, recrio as alterações do database no database somente se estiver no modo de debugging …). Neste DatabaseInitializer, os índices são criados automaticamente com base nos Atributos Exclusivos:

 Imports System.Data.Entity Imports System.Reflection Imports System.Linq Imports System.ComponentModel.DataAnnotations Public Class DatabaseInitializer Implements IDatabaseInitializer(Of DBContext) Public Sub InitializeDatabase(context As DBContext) Implements IDatabaseInitializer(Of DBContext).InitializeDatabase Dim t As Type Dim tableName As String Dim fieldName As String If Debugger.IsAttached AndAlso context.Database.Exists AndAlso Not context.Database.CompatibleWithModel(False) Then context.Database.Delete() End If If Not context.Database.Exists Then context.Database.Create() For Each pi As PropertyInfo In GetType(DBContext).GetProperties If pi.PropertyType.IsGenericType AndAlso _ pi.PropertyType.Name.Contains("DbSet") Then t = pi.PropertyType.GetGenericArguments(0) tableName = t.GetCustomAttributes(True).OfType(Of TableAttribute).FirstOrDefault.Name For Each piEntity In t.GetProperties If piEntity.GetCustomAttributes(True).OfType(Of Model.UniqueAttribute).Any Then fieldName = piEntity.Name context.Database.ExecuteSqlCommand("ALTER TABLE " & tableName & " ADD CONSTRAINT con_Unique_" & tableName & "_" & fieldName & " UNIQUE (" & fieldName & ")") End If Next End If Next End If End Sub End Class 

Talvez isso ajude …

Se você está usando o EF5 e ainda tem essa pergunta, a solução abaixo resolveu para mim.

Eu estou usando a primeira abordagem de código, colocando:

 this.Sql("CREATE UNIQUE NONCLUSTERED INDEX idx_unique_username ON dbo.Users(Username) WHERE Username IS NOT NULL;"); 

no script de migration fez bem o trabalho. Também permite valores NULL!

Com a abordagem do EF Code First, pode-se implementar suporte a restrições exclusivas baseadas em atributos usando a seguinte técnica.

Crie um atributo de marcador

 [AttributeUsage(AttributeTargets.Property)] public class UniqueAttribute : System.Attribute { } 

Marcar propriedades que você gostaria de ser única em entidades, por exemplo

 [Unique] public string EmailAddress { get; set; } 

Crie um inicializador de database ou use um já existente para criar as restrições exclusivas

 public class DbInitializer : IDatabaseInitializer { public void InitializeDatabase(DbContext db) { if (db.Database.Exists() && !db.Database.CompatibleWithModel(false)) { db.Database.Delete(); } if (!db.Database.Exists()) { db.Database.Create(); CreateUniqueIndexes(db); } } private static void CreateUniqueIndexes(DbContext db) { var props = from p in typeof(AppDbContext).GetProperties() where p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>) select p; foreach (var prop in props) { var type = prop.PropertyType.GetGenericArguments()[0]; var fields = from p in type.GetProperties() where p.GetCustomAttributes(typeof(UniqueAttribute), true).Any() select p.Name; foreach (var field in fields) { const string sql = "ALTER TABLE dbo.[{0}] ADD CONSTRAINT" + " [UK_dbo.{0}_{1}] UNIQUE ([{1}])"; var command = String.Format(sql, type.Name, field); db.Database.ExecuteSqlCommand(command); } } } } 

Defina o contexto do database para usar este inicializador no código de boot (por exemplo, em main() ou Application_Start() )

 Database.SetInitializer(new DbInitializer()); 

A solução é semelhante à do mheyman, com uma simplificação de não suportar chaves compostas. Para ser usado com o EF 5.0+.

Eu enfrentei esse problema hoje e finalmente consegui resolvê-lo. Eu não sei se é uma abordagem correta, mas pelo menos eu posso continuar:

 public class Person : IValidatableObject { public virtual int ID { get; set; } public virtual string Name { get; set; } public IEnumerable Validate(ValidationContext validationContext) { var field = new[] { "Name" }; // Must be the same as the property PFContext db = new PFContext(); Person person = validationContext.ObjectInstance as Person; var existingPerson = db.Persons.FirstOrDefault(a => a.Name == person.Name); if (existingPerson != null) { yield return new ValidationResult("That name is already in the db", field); } } } 

Use um validador de propriedade exclusivo.

 protected override DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry, IDictionary items) { var validation_state = base.ValidateEntity(entityEntry, items); if (entityEntry.Entity is User) { var entity = (User)entityEntry.Entity; var set = Users; //check name unique if (!(set.Any(any_entity => any_entity.Name == entity.Name))) {} else { validation_state.ValidationErrors.Add(new DbValidationError("Name", "The Name field must be unique.")); } } return validation_state; } 

ValidateEntity não é chamado na mesma transação do database. Portanto, pode haver condições de corrida com outras entidades no database. Você tem que hackear um pouco EF para forçar uma transação em torno do SaveChanges (e, portanto, ValidateEntity ). DBContext não pode abrir a conexão diretamente, mas o ObjectContext pode.

 using (TransactionScope transaction = new TransactionScope(TransactionScopeOption.Required)) { ((IObjectContextAdapter)data_context).ObjectContext.Connection.Open(); data_context.SaveChanges(); transaction.Complete(); } 

Como não há anotação embutida, descobri uma solução. Por favor, consulte este link para mais informações https://stackoverflow.com/a/16496291/1873113

De acordo com http://blogs.msdn.com/b/adonet/archive/2014/02/11/ef-6-1-0-beta-1-available.aspx , a EF 6.1 terá um IndexAttribute para nos ajudar .

Depois de ler esta questão, tive a minha própria questão no processo de tentar implementar um atributo para designar propriedades como chaves únicas como as respostas de Mihkel Müür , Tobias Schittkowski e mheyman sugerem: Mapear propriedades de código do Entity Framework para colunas de database (CSpace para SSpace)

Finalmente cheguei a essa resposta que pode mapear as propriedades escalares e de navegação para as colunas do database e criar um índice exclusivo em uma sequência específica designada no atributo. Esse código pressupõe que você implementou um UniqueAttribute com uma propriedade Sequence e aplicou-o às propriedades de class de entidade do EF que devem representar a chave exclusiva da entidade (diferente da chave primária).

Nota: Este código depende do EF versão 6.1 (ou posterior), que expõe EntityContainerMapping não disponível em versões anteriores.

 Public Sub InitializeDatabase(context As MyDB) Implements IDatabaseInitializer(Of MyDB).InitializeDatabase If context.Database.CreateIfNotExists Then Dim ws = DirectCast(context, System.Data.Entity.Infrastructure.IObjectContextAdapter).ObjectContext.MetadataWorkspace Dim oSpace = ws.GetItemCollection(Core.Metadata.Edm.DataSpace.OSpace) Dim entityTypes = oSpace.GetItems(Of EntityType)() Dim entityContainer = ws.GetItems(Of EntityContainer)(DataSpace.CSpace).Single() Dim entityMapping = ws.GetItems(Of EntityContainerMapping)(DataSpace.CSSpace).Single.EntitySetMappings Dim associations = ws.GetItems(Of EntityContainerMapping)(DataSpace.CSSpace).Single.AssociationSetMappings For Each setType In entityTypes Dim cSpaceEntitySet = entityContainer.EntitySets.SingleOrDefault( _ Function(t) t.ElementType.Name = setType.Name) If cSpaceEntitySet Is Nothing Then Continue For ' Derived entities will be skipped Dim sSpaceEntitySet = entityMapping.Single(Function(t) t.EntitySet Is cSpaceEntitySet) Dim tableInfo As MappingFragment If sSpaceEntitySet.EntityTypeMappings.Count = 1 Then tableInfo = sSpaceEntitySet.EntityTypeMappings.Single.Fragments.Single Else ' Select only the mapping (esp. PropertyMappings) for the base class tableInfo = sSpaceEntitySet.EntityTypeMappings.Where(Function(m) m.IsOfEntityTypes.Count _ = 1 AndAlso m.IsOfEntityTypes.Single.Name Is setType.Name).Single().Fragments.Single End If Dim tableName = If(tableInfo.StoreEntitySet.Table, tableInfo.StoreEntitySet.Name) Dim schema = tableInfo.StoreEntitySet.Schema Dim clrType = Type.GetType(setType.FullName) Dim uniqueCols As IList(Of String) = Nothing For Each propMap In tableInfo.PropertyMappings.OfType(Of ScalarPropertyMapping)() Dim clrProp = clrType.GetProperty(propMap.Property.Name) If Attribute.GetCustomAttribute(clrProp, GetType(UniqueAttribute)) IsNot Nothing Then If uniqueCols Is Nothing Then uniqueCols = New List(Of String) uniqueCols.Add(propMap.Column.Name) End If Next For Each navProp In setType.NavigationProperties Dim clrProp = clrType.GetProperty(navProp.Name) If Attribute.GetCustomAttribute(clrProp, GetType(UniqueAttribute)) IsNot Nothing Then Dim assocMap = associations.SingleOrDefault(Function(a) _ a.AssociationSet.ElementType.FullName = navProp.RelationshipType.FullName) Dim sProp = assocMap.Conditions.Single If uniqueCols Is Nothing Then uniqueCols = New List(Of String) uniqueCols.Add(sProp.Column.Name) End If Next If uniqueCols IsNot Nothing Then Dim propList = uniqueCols.ToArray() context.Database.ExecuteSqlCommand("CREATE UNIQUE INDEX IX_" & tableName & "_" & String.Join("_", propList) _ & " ON " & schema & "." & tableName & "(" & String.Join(",", propList) & ")") End If Next End If End Sub 

Para aqueles que usam as primeiras configurações de código, você também pode usar o object IndexAttribute como um ColumnAnnotation e definir sua propriedade IsUnique como true.

No exemplo:

 var indexAttribute = new IndexAttribute("IX_name", 1) {IsUnique = true}; Property(i => i.Name).HasColumnAnnotation("Index",new IndexAnnotation(indexAttribute)); 

Isso criará um índice exclusivo chamado IX_name na coluna Nome.

Desculpe pela resposta tardia, mas eu achei que era bom para você com você

Eu postei sobre isso no projeto de código

Em geral, isso depende dos atributos que você coloca nas classs para gerar seus índices exclusivos