如何在 Entity Framework Code First 中使属性唯一

Posted

技术标签:

【中文标题】如何在 Entity Framework Code First 中使属性唯一【英文标题】:How to make a property unique in Entity Framework Code First 【发布时间】:2019-05-19 23:49:00 【问题描述】:

这是我的User 模型类:

public class User 

    public int Id  get; set; 

    [Required]
    [MaxLength(100)]
    public string FullName  get; set; 

    [Required]
    [MaxLength(30)]
    [Remote("IsUsernameExists", "Home", HttpMethod = "Post")]
    public string UserName  get; set; 

    [Required]
    [RegularExpression(@"^([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]2,5)$"]
    public string Email  get; set; 

    [Required]
    [StringLength(maximumLength: 18, MinimumLength = 8)]
    public string Password  get; set; 

这是Home 控制器中的IsUsernameExists 方法

public JsonResult IsUsernameExists(string UserName)
            
    return Json(!db.Users.Any(x => x.Username == UserName), JsonRequestBehavior.AllowGet);

但它不起作用。任何进一步的帮助将不胜感激!

【问题讨论】:

不完全是什么意思?您收到任何异常或错误消息?出乎意料的结果?您需要更具体地了解您的问题。 什么也没发生。当我输入一个已经存在的用户名时,它将进入数据库并记录它 尝试使用x => x.Username == UserName.ToLowerInvariant() 并告诉我它是否有效! 还是什么都没发生 您的UserName 也可能包含空格。也可以在ToLower方法之后尝试Trim方法,看看是否有效! 【参考方案1】:

您可以使用DataAnnotationFluentApi 来创建模型属性Unique,如下所示:

使用数据注解:

[Required]
[StringLength(30)]
[Index("Ix_UserName",Order =1,IsUnique =true)]
public string UserName  get; set; 

使用 Fluent Api:

在实体框架 >= 6.2 中,

DbContext:

protected override void OnModelCreating(DbModelBuilder modelBuilder)

     base.OnModelCreating(modelBuilder);

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

在实体框架中

DbContext:

protected override void OnModelCreating(DbModelBuilder modelBuilder)

     base.OnModelCreating(modelBuilder);

     modelBuilder.Entity<User>().Property(t => t.UserName).HasMaxLength(30)
                                  .HasColumnAnnotation(IndexAnnotation.AnnotationName, new IndexAnnotation(new IndexAttribute("Ix_UserName")IsUnique = true));

记住:使用Index 属性,您还必须使用StringLength 属性。

为了使RemoteAttibute 正常工作,请在UserName 属性上写下您的RemoteAttibute,如下所示:

[Required]
[StringLength(30)]
[Index("Ix_UserName",Order =1,IsUnique =true)]
[Remote("IsUserNameExist", "Home", AdditionalFields = "Id", ErrorMessage = "User Name already exists")]
public string UserName  get; set; 

然后HomeController中的IsUserNameExist方法如下:

public JsonResult IsUserNameExist(string UserName, int? Id)

     var IsUserNameExists = db.Users.Any(x => x.UserName== UserName && x.Id != Id);
     return Json(!IsUserNameExists, JsonRequestBehavior.AllowGet);

最后确保您的视图包含以下jQuery 文件:

<script src="~/Scripts/jquery-version.min.js"></script>
<script src="~/Scripts/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>

现在一切正常!

【讨论】:

【参考方案2】:

RemoteAttribute 与实体框架没有任何关系。它只是忽略了这个属性。此外,正如文档所述,它是一个 jQuery 验证属性,它应该只适用于前端部分。

如果User 既是 MVC 模型又是数据库实体,您应该为属性创建唯一索引。一种方法是使用DbContext 中的OnModelCreating 方法:

protected override void OnModelCreating(ModelBuilder modelBuilder)

    modelBuilder.Entity<User>().HasIndex(x => new  x.Username ).IsUnique();

然后创建一个迁移,将它应用到数据库中,你就可以开始了。但是,请注意保存副本时会出现异常,并确保正确处理。

【讨论】:

【参考方案3】:

我在 HomeController 中创建了一个方法

   public bool IsUserExist(string email)
   
        return db.Users.Where(c => c.Email == email).IsAny();
    

在行动中

    if( IsUserExist(model.Email) )
    
        // my code
    

【讨论】:

以上是关于如何在 Entity Framework Code First 中使属性唯一的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Entity Framework Code First 中删除表?

如何在 Entity Framework Code First 中映射 sum 属性(如 TotalPrice)

如何在 Visual Studio Code 中安装和使用 Entity Framework Core?

如何使用 Entity Framework Code First 让我的数据库播种?

如何使用 Entity Framework Code First Fluent API 指定表名

如何在 Entity Framework Code First 中急切地包含实体的子元素和孙元素?