实体框架核心先添加唯一约束代码


152

我找不到使用属性向字段添加唯一约束的方法:

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

我正在使用这些软件包:

 "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",

Answers:


301

在EF核心上,您无法使用数据注释创建索引,但可以使用Fluent API来创建索引。

像这样在您的内部{Db}Context.cs

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

...或者如果您在buildAction中使用重载:

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

您可以在这里阅读有关它的更多信息:索引


1
非常感谢您的帮助,这是正确的解决方案!
Vadim M

如果有人登陆这里寻找在使用MS Identity模式时可以使用的解决方案,我建议在NormalizedEmail字段而不是(AspNetUsers实体的)Email上设置唯一约束。根据数据库的排序规则设置,即使使用相同的电子邮件地址,使用不同的大小写也可能无法违反约束。
汤姆(Tom)

4
这段代码不适用于字符串类型的列:(有什么方法可以在字符串列上添加唯一约束吗?
Johar Zaman

围棋的HasAlternateKey
Chamika Sandamal

1
我在进行此操作时尝试了此操作,但现在无需实现此功能。顺便说一句,谢谢您的评论。@Sampath
Johar Zaman

70

另外,如果您想在多个列上创建唯一约束,则只需执行此操作(按照@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; }
}

9

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

DB表将如下所示:

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

参考EF核心文档


11
根据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 '18


3

OP正在询问是否可以向唯一键的Entity类添加属性。简短的答案是,这是可能的,但EF核心团队没有开箱即用的功能。如果您想使用属性将唯一键添加到Entity Framework Core实体类,则可以执行我在此处发布的操作

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

[UniqueKey]属性是Microsoft定义的属性吗?还是应该自己定义?
Mohammed Osman

[UniqueKey]属性是我开发的自定义属性,用于在.cs实体类中添加唯一键(而不是通过DbContext的OnModelCreating()方法)
Justin Tubbs

3
那很棒。您能否输入您开发的自定义属性的代码?
Mohammed Osman


2

对于尝试所有这些解决方案但不起作用的人,请尝试此解决方案,它对我有用

protected override void OnModelCreating(ModelBuilder builder)
{

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

}

2

通过模型配置在EF核心中使用它

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

1

在.NET Core 2.2中,这些方法都不适合我,但是我能够修改一些代码,以定义一个不同的主键来实现此目的。

在下面的实例中,我要确保OutletRef字段是唯一的:

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

这将在数​​据库中添加所需的唯一索引。但是,它没有提供指定自定义错误消息的功能。


0

我们可以使用流利的api添加唯一键索引。下面的代码为我工作

protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {

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

    }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.