实体框架代码第一个唯一列

时间:2012-05-16 08:20:49

标签: entity-framework data-annotations entity-framework-4.3

我正在使用Entity Framework 4.3并使用Code Fist。

我有一个班级

public class User
{
   public int UserId{get;set;}
   public string UserName{get;set;}
}

如何在创建数据库表时告诉Entity Framework UserName必须是唯一的? 如果可能的话,我更愿意使用数据分析而不是配置文件。

6 个答案:

答案 0 :(得分:218)

在Entity Framework 6.1+中,您可以在模型上使用此属性:

[Index(IsUnique=true)]

您可以在此命名空间中找到它:

using System.ComponentModel.DataAnnotations.Schema;

如果您的模型字段是字符串,请确保它在SQL Server中未设置为nvarchar(MAX),否则您将在Entity Framework Code First中看到此错误:

  

表'dbo.y'中的列'x'的类型无效,无法用作索引中的键列。

原因在于:

  

SQL Server保留所有索引键列的最大总大小的900字节限制。“

(来自:http://msdn.microsoft.com/en-us/library/ms191241.aspx

您可以通过在模型上设置最大字符串长度来解决此问题:

[StringLength(450)]

您的模型现在将在EF CF 6.1 +中显示:

public class User
{
   public int UserId{get;set;}
   [StringLength(450)]
   [Index(IsUnique=true)]
   public string UserName{get;set;}
}

<强>更新

如果您使用Fluent:

  public class UserMap : EntityTypeConfiguration<User>
  {
    public UserMap()
    {
      // ....
      Property(x => x.Name).IsRequired().HasMaxLength(450).HasColumnAnnotation("Index", new IndexAnnotation(new[] { new IndexAttribute("Index") { IsUnique = true } }));
    }
  }

并在你的modelBuilder中使用:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
  // ...
  modelBuilder.Configurations.Add(new UserMap());
  // ...
}

更新2

for EntityFrameworkCore也请参阅此主题:https://github.com/aspnet/EntityFrameworkCore/issues/1698

更新3

对于EF6.2,请参阅:https://github.com/aspnet/EntityFramework6/issues/274

更新4

使用EF Core的ASP.NET Core Mvc 2.2:

[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Unique { get; set; }

答案 1 :(得分:25)

EF不支持键以外的唯一列。如果您正在使用EF迁移,则可以强制EF在UserName列上创建唯一索引(在迁移代码中,而不是通过任何批注),但唯一性将仅在数据库中强制实施。如果您尝试保存重复值,则必须捕获数据库触发的异常(约束违规)。

答案 2 :(得分:9)

从您的代码中可以看出您使用POCO。拥有另一个密钥是不必要的:您可以按照juFo的建议添加索引。
如果您使用Fluent API而不是归因于UserName属性,则列注释应如下所示:

this.Property(p => p.UserName)
    .HasColumnAnnotation("Index", new IndexAnnotation(new[] { 
        new IndexAttribute("Index") { IsUnique = true } 
    }
));

这将创建以下SQL脚本:

CREATE UNIQUE NONCLUSTERED INDEX [Index] ON [dbo].[Users]
(
    [UserName] ASC
)
WITH (
    PAD_INDEX = OFF, 
    STATISTICS_NORECOMPUTE = OFF, 
    SORT_IN_TEMPDB = OFF, 
    IGNORE_DUP_KEY = OFF, 
    DROP_EXISTING = OFF, 
    ONLINE = OFF, 
    ALLOW_ROW_LOCKS = ON, 
    ALLOW_PAGE_LOCKS = ON
) ON [PRIMARY]

如果您尝试插入多个具有相同UserName的用户,则会收到DbUpdateException,并显示以下消息:

Cannot insert duplicate key row in object 'dbo.Users' with unique index 'Index'. 
The duplicate key value is (...).
The statement has been terminated.

同样,版本6.1之前的实体框架中没有列注释。

答案 3 :(得分:5)

请注意,在Entity Framework 6.1(目前处于测试阶段)中,将支持IndexAttribute注释索引属性,这将自动导致Code First Migrations中的(唯一)索引。

答案 4 :(得分:1)

在使用FluentAPI的EF 6.2 中,您可以使用HasIndex()

modelBuilder.Entity<User>().HasIndex(u => u.UserName).IsUnique();

答案 5 :(得分:-13)

EF4.3的解决方案

唯一身份名称

在列上添加数据注释:

 [Index(IsUnique = true)]
 [MaxLength(255)] // for code-first implementations
 public string UserName{get;set;}

唯一ID ,  我在我的专栏上添加了装饰[Key]并完成了。  与此处描述的解决方案相同:https://msdn.microsoft.com/en-gb/data/jj591583.aspx

IE:

[Key]
public int UserId{get;set;}

替代答案

使用数据注释

[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Column("UserId")]

使用映射

  mb.Entity<User>()
            .HasKey(i => i.UserId);
        mb.User<User>()
          .Property(i => i.UserId)
          .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
          .HasColumnName("UserId");