代码首先为必填字段生成可为空的列

Posted

技术标签:

【中文标题】代码首先为必填字段生成可为空的列【英文标题】:Code first generate nullable columns for Required fileds 【发布时间】:2021-12-25 02:03:10 【问题描述】:

我有下一个 C# 代码第一类字段定义(.NET 5):

[Required]
public Visa Visa  get; set; 

[Required]
public Embassy Embassy  get; set; 

尽管需要属性 EF 生成可为空的 DB 列:

VisaId = table.Column<int>(type: "int", nullable: true),
EmbassyId = table.Column<int>(type: "int", nullable: true),

如何解决这个问题并使其不为空?在其他类中类似的代码,它按预期工作。

感谢您的帮助!

【问题讨论】:

这里没有显示任何流畅的配置?还是显式可为空的 FK 属性(如 public int? VisaId get; set; )? 嗨,Ivan,在快照中我得到的只是: b.Property("VisaId") .HasColumnType("int"); b.Property("EmbassyId") .HasColumnType("int"); 所以我正在寻找在迁移中获取 table.Column(nullable: false) 的方法 这很奇怪,因为快照和迁移应该匹配。您是否再次尝试Remove-MigrationAdd-Migration 嗨伊万。是的,我做到了。尝试删除并重新添加迁移。现在为 VS 安装更新 :) 【参考方案1】:

如果您没有在实体中指定外键,EFCore 将生成一个默认可以为空的影子属性(正如您目前在 .NET 5 中看到的那样)。

如果您继续使用 .NET 5,有几种方法可以为您的实体生成不可为空的列。

我们可以显式地创建外键属性。

public int VisaId  get; set; 
public Visa Visa  get; set; 

或者您可以在 DbContext 中流畅地指定它并使用IsRequired()

public class MyContext : DbContext

    public DbSet<MyEntity> MyEntities  get; set; 
    public DbSet<Visa> Visas  get; set; 

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

        modelBuilder.Entity<MyEntity>().Property<int>("VisaId").IsRequired();
    

如果您没有卡在 .NET 5 上并且可以迁移到 .NET 6,EFCore 是完全 NRT 注释的,并且会像这样进行迁移。将&lt;Nullable&gt;enable&lt;Nullable&gt; 添加到您的项目文件或在实体文件的顶部添加#nullable enable。重新生成迁移,您应该会看到自动生成的列不可为空。

更新:

我进行了更多调查,以尝试重新创建您的原始情况,即您的原始类确实有一些不可为空的列。

[Required] 注释似乎真的依赖于目标框架和您正在使用的 EFCore 版本。

这是我的示例类

    public class MyContext : DbContext
    
        public DbSet<Country> Countries  get; set; 
        public DbSet<Visa> Visas  get; set; 
        public DbSet<Person> Persons  get; set; 

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        
            optionsBuilder.UseSqlServer("this is one bad connectiong string");
        
    

    public class Country
    
        public int Id  get; set; 
    

    public class Visa
    
        public int Id  get; set; 
    

    public class Person
    
        public int Id  get; set; 
        [Required]
        public Visa Visa  get; set; 
        public Country Country  get; set; 
    

我正在使用 SDK 风格的控制台应用程序来生成迁移。

在以下框架和 efcore 版本的所有中,启用Nullable Contexts 会使生成的列具有带注释的可空性。这是 IMO 最简单的修复方法。

使用net48netcoreapp3.1net5.0net6.0和EFCore 3.1.21,Required注解确实有效果。

相关生成表:

            migrationBuilder.CreateTable(
                name: "Persons",
                columns: table => new
                
                    Id = table.Column<int>(nullable: false)
                        .Annotation("SqlServer:Identity", "1, 1"),
                    VisaId = table.Column<int>(nullable: false),
                    CountryId = table.Column<int>(nullable: true)
                ,

我只是更新 TFM 和 EFCore 版本,删除现有迁移并重新生成它们。 这是我以表格形式总结的发现

TFM EFCore nullable: VisaId nullable: CountryId
net48, netcoreapp3.1, net5.0, net6.0 3.1.21 false true
netcoreapp3.1, net5.0, net6.0 5.0.12 true true
net6.0 6.0.0 false true

希望这有助于澄清您的情况!

【讨论】:

奇怪的是,在我的相邻班级中,我有:` [必需] public Country Country get;放; ` 它会生成: ` migrationBuilder.AddColumn( name: "CountryId", table: "Embassy", nullable: false, defaultValue: 0); ` 但在快照中 ` b.Property("CountryId") .HasColumnType("int"); ` 这些类的描述几乎相似:) 您是否碰巧在另一个目标框架或 efcore 版本上生成了其他迁移?如果我将测试项目更改为 net48(仅支持 EFCore 3.1),那么 Required 注释实际上确实使列不可为空,而无需手动指定 shadow 属性。 @smatveev 检查我的更新。我想你可能会发现它很有用。 感谢汉克的更新。太棒了!这正是我正在处理的问题

以上是关于代码首先为必填字段生成可为空的列的主要内容,如果未能解决你的问题,请参考以下文章

中继/ graphql:可为空的响应或捕获查询错误的方法

在 Django 中将模型字段设置为必填

SQL 在 Where 子句中处理可为空的外键

堆栈溢出错误可为空的数字类型c#

解构可为空的对象

newtonjson序列化空DataTable 没有字段