Entity Framework Core ajoute une contrainte unique au code d'abord

152

Je ne trouve pas de moyen d'ajouter une contrainte unique à mon champ avec l'attribut using:

public class User
{
    [Required]
    public int Id { get; set; }

    [Required]
    // [Index("IX_FirstAndSecond", 2, IsUnique = true)] not supported by core
    public string Email { get; set; }

    [Required]
    public string Password { get; set; }
}

J'utilise ces packages:

 "Microsoft.EntityFrameworkCore": "1.0.1",
 "Microsoft.EntityFrameworkCore.SqlServer": "1.0.1",
 "Microsoft.EntityFrameworkCore.SqlServer.Design": "1.0.1",
 "Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final",
Vadim M
la source
Des exemples d' API
Michael Freidgeim

Réponses:

301

Sur EF Core, vous ne pouvez pas créer d'index à l'aide d'annotations de données, mais vous pouvez le faire à l'aide de l'API Fluent.

Comme ça dans votre {Db}Context.cs:

protected override void OnModelCreating(ModelBuilder builder)
{
    builder.Entity<User>()
        .HasIndex(u => u.Email)
        .IsUnique();
}

... ou si vous utilisez la surcharge avec buildAction:

protected override void OnModelCreating(ModelBuilder builder)
{
    builder.Entity<User>(entity => {
        entity.HasIndex(e => e.Email).IsUnique();
    });
}

Vous pouvez en savoir plus ici: Index

Sampath
la source
1
Merci beaucoup pour votre aide, c'est la bonne solution!
Vadim M
Au cas où quelqu'un atterrirait ici à la recherche d'une solution qui fonctionne lors de l'utilisation du schéma MS Identity, je suggère de définir la contrainte unique sur le champ NormalizedEmail, et non sur Email (de l'entité AspNetUsers). L'utilisation d'une casse différente peut ne pas violer la contrainte même s'il s'agit de la même adresse e-mail, en fonction du paramètre de classement de la base de données.
Tom
4
Ce code ne fonctionne pas pour la colonne de type string: (Y a-t-il un moyen d'ajouter une contrainte unique sur la colonne de chaîne?
Johar Zaman
Allez-yHasAlternateKey
Chamika Sandamal
1
J'ai essayé ceci quand je travaillais là-dessus mais maintenant je n'ai plus besoin de l'implémenter. Btw Merci pour votre commentaire. @Sampath
Johar Zaman
70

De plus, si vous souhaitez créer des contraintes uniques sur plusieurs colonnes, vous pouvez simplement le faire (en suivant le lien @ Sampath )

class MyContext : DbContext
{
    public DbSet<Person> People { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Person>()
            .HasIndex(p => new { p.FirstName, p.LastName })
            .IsUnique(true);
    }
}

public class Person
{
    public int PersonId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}
Hossein Narimani Rad
la source
9

Solution pour EF Core

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Passport { get; set; }
}

public class ApplicationContext : DbContext
{
    public DbSet<User> Users { get; set; }
    public ApplicationContext()
    {
        Database.EnsureCreated();
    }
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=efbasicsappdb;Trusted_Connection=True;");
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<User>().HasAlternateKey(u => u.Passport);
        //or: modelBuilder.Entity<User>().HasAlternateKey(u => new { u.Passport, u.Name})
    }
}

La table DB ressemblera à ceci:

CREATE TABLE [dbo].[Users] (
    [Id]       INT            IDENTITY (1, 1) NOT NULL,
    [Name]     NVARCHAR (MAX) NULL,
    [Passport] NVARCHAR (450) NOT NULL,
    CONSTRAINT [PK_Users] PRIMARY KEY CLUSTERED ([Id] ASC),
    CONSTRAINT [AK_Users_Passport] UNIQUE NONCLUSTERED ([Passport] ASC)
);

Référez-vous à la documentation EF Core

Evgeniy Miroshnichenko
la source
11
Selon la documentation EF Core:If you just want to enforce uniqueness of a column then you want a unique index rather than an alternate key. In EF, alternate keys provide greater functionality than unique indexes because they can be used as the target of a foreign key.
bigworld12
Référence au commentaire de bigworld12
granadaCoder
3

L'OP demande s'il est possible d'ajouter un attribut à une classe d'entité pour une clé unique. La réponse courte est que c'est possible, mais pas une fonctionnalité prête à l'emploi de l'équipe EF Core. Si vous souhaitez utiliser un attribut pour ajouter des clés uniques à vos classes d'entité Entity Framework Core, vous pouvez faire ce que j'ai publié ici

public class Company
{
    [Required]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid CompanyId { get; set; }

    [Required]
    [UniqueKey(groupId: "1", order: 0)]
    [StringLength(100, MinimumLength = 1)]
    public string CompanyName { get; set; }

    [Required]
    [UniqueKey(groupId: "1", order: 1)]
    [StringLength(100, MinimumLength = 1)]
    public string CompanyLocation { get; set; }
}
Justin Tubbs
la source
L'attribut [UniqueKey] est un attribut défini par Microsoft? ou doit-on le définir lui-même?
Mohammed Osman
L'attribut [UniqueKey] est un attribut personnalisé que j'ai développé pour permettre l'ajout de clés uniques dans les classes d'entités .cs (et non via la méthode OnModelCreating () de DbContext)
Justin Tubbs
3
C'est génial. Pourriez-vous s'il vous plaît mettre le code de l'attribut personnalisé que vous avez développé?!
Mohammed Osman
2

Pour quelqu'un qui essaie toutes ces solutions mais ne fonctionne pas, essayez celle-ci, cela a fonctionné pour moi

protected override void OnModelCreating(ModelBuilder builder)
{

    builder.Entity<User>().Property(t => t.Email).HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute("IX_EmailIndex") { IsUnique = true }));

}
Shonie
la source
2

Pour l'utiliser dans EF Core via la configuration du modèle

public class ApplicationCompanyConfiguration : IEntityTypeConfiguration<Company>
{
    public void Configure(EntityTypeBuilder<Company> builder)
    {
        builder.ToTable("Company"); 
        builder.HasIndex(p => p.Name).IsUnique();
    }
}
valentasme
la source
1

Aucune de ces méthodes n'a fonctionné pour moi dans .NET Core 2.2, mais j'ai pu adapter un peu de code que j'avais pour définir une clé primaire différente pour fonctionner à cette fin.

Dans l'exemple ci-dessous, je veux m'assurer que le champ OutletRef est unique:

public class ApplicationDbContext : IdentityDbContext
    {
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            modelBuilder.Entity<Outlet>()
                .HasIndex(o => new { o.OutletRef });
        }
    }

Cela ajoute l'index unique requis dans la base de données. Cependant, il ne permet pas de spécifier un message d'erreur personnalisé.

Robin Wilson
la source
0

Nous pouvons ajouter un index de clé unique en utilisant une API fluide. Le code ci-dessous a fonctionné pour moi

protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {

        modelBuilder.Entity<User>().Property(p => p.Email).HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute("IX_EmailIndex") { IsUnique = true }));

    }
Kuldeep Singh
la source
0

Le noyau EF prend en charge plusieurs clés uniques

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
  modelBuilder.Entity<Account>()
      .HasKey(item => new { item.Email, item.RoleId });
}

N'oubliez pas d'exécuter la commande ef core pour effectuer la migration et mettre à jour la base de données

>> dotnet ef migrations add MigrationName -c YourDbContextName
>> dotnet ef database update -c YourDbContextName
kdgilang
la source