为啥Required IdentityUser 属性会导致可以为空的数据库字段?

Posted

技术标签:

【中文标题】为啥Required IdentityUser 属性会导致可以为空的数据库字段?【英文标题】:Why does a Required IdentityUser property result in a nullable database field?为什么Required IdentityUser 属性会导致可以为空的数据库字段? 【发布时间】:2021-09-03 20:11:20 【问题描述】:

我想要求特定类型的所有实体在我的 ASP.NET MVC 应用程序中都有相应的用户,并且这是在数据库级别强制执行的,即作为不可为空的字段。但是,当我在模型类的 IdentityUser 属性上设置 Required 属性时,如下所示:

using Microsoft.AspNetCore.Identity;
using System.ComponentModel.DataAnnotations;

namespace Test.Models

    public class Foo
    
        public int Id  get; set; 

        [Required]
        public IdentityUser User  get; set; 
    

生成的相应迁移将UserId 表字段设置为可为空:

UserId = table.Column<string>(type: "TEXT", nullable: true)

我已经读过 Table Per Hierarchy 会导致这种情况,但我没有使用任何继承。

我错过了什么?有没有办法实现我想要的?

【问题讨论】:

DbContext.OnModelConfiguring中明确设置属性是否有效? 请给全班看好吗? @abdusco 我在 API 文档中找不到对 OnModelConfiguring 的任何引用。 @Serge 我已经添加了整个类代码。 【参考方案1】:

您还可以使用Fluent API 来配置您的约束。

public class Foo

    public int Id  get; set; 

    public string UserId  get; set; 

    public IdentityUser User  get; set; 


public class ApplicationDbContext : IdentityDbContext<ApplicationUser>

    public ApplicationDbContext()
        : base("DefaultConnection", throwIfV1Schema: false)
    
    

    public DbSet<Foo> Foos  get; set; 

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<Foo>()
            .HasRequired(c => c.User)
            .WithMany(d => d.Foos)
            .HasForeignKey(c => c.UserId);
    
   

【讨论】:

【参考方案2】:

尝试修复你的课程

public class Foo
     
        [Key]
        public int Id  get; set; 
        
       [Required]
        public string UserId  get; set; 

       [ForeignKey(nameof(UserId))]
        public IdentityUser User  get; set; 
    

Net 5 自动创建一个影子属性 UserId 以便您可以保存您的 Foo 类。由于您使用了 [Required],EF 自动添加它可以为空。如果此属性不能为 null(例如,如果它是 int 类型(不是 int?!)),则不需要 [Required] 属性。

【讨论】:

IdentityUser 主键是一个字符串,而不是一个 int。 感谢您的回答。你知道为什么需要额外的财产吗?为什么我不能将Required 属性放在User 上并且它可以工作? @SimonMorgan 因为您无法将整个用户记录保存在 Foo 数据库表中。您只能保存一列值。保存主键是在需要加入时查找用户的最佳方式。 Net 5 可以创建影子属性 UserId,但最好控制它。 但即使没有 UserId 属性,EF 也发现它是 AspNetUsers 表的外键并在 Foo 表上创建了一个 UserId 字段,但它设置为可为空,即使User 属性为 [Required]。那么为什么你必须显式地向模型添加一个UserId 属性并将that 设置为[Required] 以将数据库UserId 字段设置为不可为空? 是的,正如我已经说过的,它被称为影子属性,它仅用于保存。但是最好明确地添加它,以便您可以在代码中使用它。例如,如果您只需要一个 userId,则不需要包含整个用户记录。

以上是关于为啥Required IdentityUser 属性会导致可以为空的数据库字段?的主要内容,如果未能解决你的问题,请参考以下文章

为啥调用vector.reserve(required + 1) 比vector.reserve(required) 快?

为啥在 Protocol Buffers 3 中删除了 required 和 optional

required_once() 中的变量未定义但可与 require() 一起使用,为啥?

linux rsync 同步过来的目录为啥属主属组是mysql

为啥Django在使用@login_required装饰器时有太多的登录重定向?

为啥这违反了类型参数“TUser”的约束?