Contrainte unique dans l’entité Framework Code First

Question

Est-il possible de définir une contrainte unique sur une propriété en utilisant soit la syntaxe courante, soit un atsortingbut? Si non, quelles sont les solutions de contournement?

J’ai une classe d’utilisateurs avec une clé primaire, mais je voudrais m’assurer que l’adresse e-mail est également unique. Est-ce possible sans éditer directement la firebase database?

Solution (basée sur la réponse de Matt)

public class MyContext : DbContext { public DbSet Users { get; set; } public override int SaveChanges() { foreach (var item in ChangeTracker.Ensortinges()) 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)"); } } } } 

Pour autant que je sache, il n’y a aucun moyen de le faire avec Entity Framework pour le moment. Cependant, il ne s’agit pas seulement d’un problème avec des contraintes uniques … vous souhaiterez peut-être créer des index, vérifier des contraintes et éventuellement des déclencheurs et d’autres constructions. Voici un modèle simple que vous pouvez utiliser avec votre première installation de code, même s’il est vrai que ce n’est pas agnostique à la firebase 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..."); } } } } 

Une autre option est que si votre modèle de domaine est la seule méthode d’insertion / mise à jour de données dans votre firebase database, vous pouvez implémenter vous-même l’exigence d’unicité et laisser la firebase database à l’extérieur. Il s’agit d’une solution plus portable qui vous oblige à définir clairement les règles de votre entreprise dans votre code, mais laisse votre firebase database ouverte aux données non valides.

À partir de EF 6.1, il est maintenant possible:

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

Cela vous donnera un index unique au lieu d’une contrainte unique, à proprement parler. Dans la plupart des cas, ils sont identiques .

Pas vraiment lié à cela, mais cela pourrait aider dans certains cas.

Si vous souhaitez créer un index composite unique sur 2 colonnes, par exemple, qui agira comme une contrainte pour votre table, vous pouvez utiliser le nouveau mécanisme de migration à partir de la version 4.3:

Fondamentalement, vous devez insérer un appel comme celui-ci dans l’un de vos scripts de migration:

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

Quelque chose comme ca:

 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" }); } } } 

Je fais un hack complet pour que SQL soit exécuté lors de la création de la firebase database. Je crée mon propre DatabaseInitializer et hérite de l’un des initialiseurs fournis.

 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; } } 

C’est le seul endroit que je pourrais trouver dans mes instructions SQL.

Ceci vient de CTP4. Je ne sais pas comment cela fonctionne dans CTP5.

En essayant de savoir s’il y avait un moyen de le faire, seule la façon dont je l’ai trouvé était mise en application, j’ai créé un atsortingbut à append à chaque classe où vous indiquez le nom des champs que vous devez être uniques:

  [System.AtsortingbuteUsage(System.AtsortingbuteTargets.Class, AllowMultiple=false,Inherited=true)] public class UniqueAtsortingbute:System.Atsortingbute { private ssortingng[] _atts; public ssortingng[] KeyFields { get { return _atts; } } public UniqueAtsortingbute(ssortingng keyFields) { this._atts = keyFields.Split(new char[]{','}, SsortingngSplitOptions.RemoveEmptyEnsortinges); } } 

Puis dans ma classe je vais l’append:

 [CustomAtsortingbutes.Unique("Name")] public class Item: BasePOCO { public ssortingng Name{get;set;} [SsortingngLength(250)] public ssortingng Description { get; set; } [Required] public Ssortingng Category { get; set; } [Required] public ssortingng UOM { get; set; } [Required] } 

Enfin, je vais append une méthode dans mon référentiel, dans la méthode Add ou lors de l’enregistrement de modifications comme ceci:

 private void ValidateDuplicatedKeys(T entity) { var atts = typeof(T).GetCustomAtsortingbutes(typeof(UniqueAtsortingbute), 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"); } } } } 

Pas trop sympa car nous devons compter sur la reflection, mais pour l'instant, c'est l'approche qui fonctionne pour moi! = D

De plus, en 6.1, vous pouvez utiliser la version de syntaxe courante de la réponse de @ mihkelmuur comme suit:

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

La méthode courante n’est pas parfaite à l’OMI mais au moins, c’est possible maintenant.

Plus de deets sur le blog d’Arthur Vickers http://blog.oneunicorn.com/2014/02/15/ef-6-1-creating-indexes-with-indexatsortingbute/

Un moyen simple en Visual Basic utilisant EF5 Code First Migrations

Exemple de classe publique

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

Classe de fin

L’atsortingbut MaxLength est très important pour l’index unique du type de chaîne

Exécuter cmd: update-database -verbose

après exécution cmd: add-migration 1

dans le fichier généré

 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 

Semblable à la réponse de Tobias Schittkowski, mais C # et a la capacité d’avoir plusieurs champs dans la construction.

Pour l’utiliser, placez un [Unique] sur n’importe quel champ que vous souhaitez être unique. Pour les chaînes, vous devrez faire quelque chose comme (notez l’atsortingbut MaxLength):

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

car le champ de chaîne par défaut est nvarchar (max) et ne sera pas autorisé dans une clé.

Pour plusieurs champs de la contrainte, vous pouvez faire:

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

Tout d’abord, le UniqueAtsortingbute:

 ///  /// The unique atsortingbute. Use to mark a field as unique. The ///  looks for this atsortingbute to /// create unique constraints in tables. ///  internal class UniqueAtsortingbute : Atsortingbute { ///  /// 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 ssortingng 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; } } 

Ensuite, incluez une extension utile pour obtenir le nom de la table de firebase database à partir d’un type:

 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 = ...; /// ssortingng table = context.GetTableName<Foo>(); ///  ///  ///  /// This code uses ObjectQuery.ToTraceSsortingng to generate an SQL /// select statement for an entity, and then extract the table /// name from that statement. ///  ///  public static ssortingng 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 = ...; /// ssortingng table = context.GetTableName<Foo>(); ///  ///  ///  /// This code uses ObjectQuery.ToTraceSsortingng to generate an SQL /// select statement for an entity, and then extract the table /// name from that statement. ///  ///  public static ssortingng 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 = (ssortingng)objectSet.GetType() .GetMethod("ToTraceSsortingng", takesNoParameters) .Invoke(objectSet, noParams); Match match = Regex.Match(sql, @"FROM\s+(.*)\s+AS", RegexOptions.IgnoreCase); return match.Success ? match.Groups[1].Value : null; } } 

Ensuite, l’initialiseur de firebase 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 UniqueAtsortingbute /// and uses those and the table name to build the TSQL ssortingngs. ///  ///  /// 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, ssortingng 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.GetCustomAtsortingbutes(true) .OfType().FirstOrDefault(); if (unique != null) { ssortingng fieldName = entityPropertyInfo.Name; // use the name field in the UniqueAtsortingbute or create a // name if none is given ssortingng constraintName = unique.Name ?? ssortingng.Format( "constraint_{0}_unique_{1}", tableName .Replace("[", ssortingng.Empty) .Replace("]", ssortingng.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 => ssortingng.Format( "ALTER TABLE {0} ADD CONSTRAINT {1} UNIQUE ({2})", tableName, uc.Key, ssortingng.Join(",", uc.Value.Select(v => v.Item2)))); } } 

Si vous remplacez la méthode ValidateEntity dans votre classe DbContext, vous pouvez également y placer la logique. L’avantage est que vous aurez un access complet à tous vos jeux de données. Voici un exemple:

 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] [SsortingngLength(50)] public ssortingng 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; } } } 

J’ai résolu le problème par reflection (désolé, mes amis, VB.Net …)

Tout d’abord, définissez un atsortingbut UniqueAtsortingbute:

  _ Public Class UniqueAtsortingbute Inherits Atsortingbute End Class 

Ensuite, améliorez votre modèle comme

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

Enfin, créez un DatabaseInitializer personnalisé (dans ma version, je recrée la firebase database sur les modifications de firebase database uniquement en mode débogage …). Dans cet DatabaseInitializer, les index sont automatiquement créés en fonction des atsortingbuts uniques:

 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 Ssortingng Dim fieldName As Ssortingng 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.GetCustomAtsortingbutes(True).OfType(Of TableAtsortingbute).FirstOrDefault.Name For Each piEntity In t.GetProperties If piEntity.GetCustomAtsortingbutes(True).OfType(Of Model.UniqueAtsortingbute).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 

Peut-être que cela aide …

Si vous utilisez EF5 et que vous avez toujours cette question, la solution ci-dessous a résolu le problème pour moi.

J’utilise l’approche du code d’abord, en mettant donc:

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

dans le script de migration a bien fait le travail. Il autorise également les valeurs NULL!

Avec l’approche par code EF, on peut implémenter un support de contrainte unique basé sur des atsortingbuts en utilisant la technique suivante.

Créer un atsortingbut de marqueur

 [AtsortingbuteUsage(AtsortingbuteTargets.Property)] public class UniqueAtsortingbute : System.Atsortingbute { } 

Marquer les propriétés que vous souhaitez être uniques sur les entités, par exemple

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

Créer un initialiseur de firebase database ou en utiliser un existant pour créer les contraintes uniques

 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); } } } } 

Définissez le contexte de votre firebase database pour utiliser cet initialiseur dans le code de démarrage (par exemple, dans main() ou Application_Start() )

 Database.SetInitializer(new DbInitializer()); 

La solution est similaire à celle de Mheyman, avec une simplification de la non prise en charge des clés composites. À utiliser avec EF 5.0+.

J’ai fait face à ce problème aujourd’hui et j’ai finalement réussi à le résoudre. Je ne sais pas si c’est une bonne approche mais au moins je peux continuer:

 public class Person : IValidatableObject { public virtual int ID { get; set; } public virtual ssortingng 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); } } } 

Utilisez un validateur de propriété unique.

 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’est pas appelé dans la même transaction de firebase database. Par conséquent, il peut exister des conditions de concurrence avec d’autres entités de la firebase database. Vous devez pirater un peu EF pour forcer une transaction autour de SaveChanges (et donc, ValidateEntity ). DBContext ne peut pas ouvrir la connexion directement, mais ObjectContext peut le faire.

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

Comme il n’y a pas d’annotation intégrée, j’ai trouvé une solution. S’il vous plaît se référer à ce lien pour plus d’informations https://stackoverflow.com/a/16496291/1873113

Selon http://blogs.msdn.com/b/adonet/archive/2014/02/11/ef-6-1-0-beta-1-available.aspx , EF 6.1 aura un IndexAtsortingbute pour nous aider .

Après avoir lu cette question, j’ai eu ma propre question en essayant d’implémenter un atsortingbut pour désigner des propriétés comme des clés uniques comme celles de Mihkel Müür , Tobias Schittkowski et mheyman: Mappez les propriétés du code Entity Framework aux colonnes de firebase database

Je suis finalement arrivé à cette réponse qui peut mapper les propriétés scalaires et de navigation jusqu’aux colonnes de firebase database et créer un index unique dans une séquence spécifique désignée sur l’atsortingbut. Ce code suppose que vous avez implémenté UniqueAtsortingbute avec une propriété Sequence et l’a appliqué aux propriétés de classe d’entité EF qui doivent représenter la clé unique de l’entité (autre que la clé primaire).

Remarque: Ce code repose sur EF version 6.1 (ou ultérieure) qui expose EntityContainerMapping non disponible dans les versions précédentes.

 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 Ssortingng) = Nothing For Each propMap In tableInfo.PropertyMappings.OfType(Of ScalarPropertyMapping)() Dim clrProp = clrType.GetProperty(propMap.Property.Name) If Atsortingbute.GetCustomAtsortingbute(clrProp, GetType(UniqueAtsortingbute)) IsNot Nothing Then If uniqueCols Is Nothing Then uniqueCols = New List(Of Ssortingng) uniqueCols.Add(propMap.Column.Name) End If Next For Each navProp In setType.NavigationProperties Dim clrProp = clrType.GetProperty(navProp.Name) If Atsortingbute.GetCustomAtsortingbute(clrProp, GetType(UniqueAtsortingbute)) 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 Ssortingng) 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 & "_" & Ssortingng.Join("_", propList) _ & " ON " & schema & "." & tableName & "(" & Ssortingng.Join(",", propList) & ")") End If Next End If End Sub 

Pour ceux qui utilisent les premières configurations de code, vous pouvez également utiliser l’object IndexAtsortingbute en tant que ColumnAnnotation et définir sa propriété IsUnique sur true.

Par exemple:

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

Cela créera un index unique nommé IX_name dans la colonne Nom.

Désolé pour la réponse tardive mais j’ai trouvé ça bien

J’ai posté sur ce projet de code

En général, cela dépend des atsortingbuts que vous mettez sur les classes pour générer vos index uniques