EF Core 5 HasDefaultValue 问题,当值设置为 .Net 类型默认值时,ef 推送默认值

ufo*_*cat 5 c# oracle entity-framework-core

我在使用实体框架核心插入具有默认值列的记录时遇到了一个奇怪的问题。有没有其他方法来获得预期的行为,我是否错过了一些愚蠢的事情?

tldr:设置 int 属性 = 0 或 bool 为 true 会导致新字符串使用默认值 string.empty 给出 ORA-01400: 无法插入 NULL (这似乎是 Oracle 的事情)

场景:使用迁移添加新列并添加新记录会导致正常行为(插入默认值)

仅添加新记录提供的旧字段=确定 "ID" : 6, "OLDFIELD" : "ef test 1", "NEWINT" : 5, "NEWSTRING" : "def", "NEWBOOLFALSE" : 0, "NEWBOOLTRUE" : 1

添加与 .Net 默认值不同的值也有效 "ID" : 12, "OLDFIELD" : "ef test all set", "NEWINT" : 42, "NEWSTRING" : "string here", "NEWBOOLFALSE" : 1, "NEWBOOLTRUE" : 1

现在,当您为 int 指定 0 并为 bool 指定 false 时会出现问题

var test = new TestDef()
        {
            OldField = "ef bad test",
            NewInt = 0,
            NewBoolFalse = false,
            NewBoolTrue = false
        };
_womaDbContext.Add(test);
await _womaDbContext.SaveChangesAsync();
Run Code Online (Sandbox Code Playgroud)

你得到"ID" : 36, "OLDFIELD" : "ef bad test", "NEWINT" : 5, "NEWSTRING" : "def", "NEWBOOLFALSE" : 0, "NEWBOOLTRUE" : 1

NewString = string.Empty 给出 oracle 异常 ORA-01400: 无法插入 NULL (这似乎是 oracle 的事情)

插入查询工作正常

INSERT INTO WOMA_SCHEMA.TESTDEF
(ID, OLDFIELD, NEWINT, NEWBOOLFALSE, NEWBOOLTRUE)
VALUES("WOMA_SCHEMA"."ISEQ$$_42048".nextval, 'sql empty',0, 0,0);
Run Code Online (Sandbox Code Playgroud)

这使得在不进行更新的情况下不可能在 NEWBOOLTRUE 中插入假值或在 NEWINT 中插入 0

测试类(DbContext OnModelCreating 调用 TestDef.OnModelCreating(modelBuilder)):

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;

namespace Test.Model
{
    [Table("TESTDEF")]
    public class TestDef
    {
        [Column("ID")]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }

        [Column("OLDFIELD")]
        public string OldField { get; set; }

        [Required]
        [Column("NEWINT")]
        public int NewInt { get; set; }

        [Required]
        [Column("NEWSTRING")]
        public string NewString { get; set; }

        [Required]
        [Column("NEWBOOLTRUE")]
        public bool NewBoolTrue { get; set; }

        [Required]
        [Column("NEWBOOLFALSE")]
        public bool NewBoolFalse { get; set; }

        public static void OnModelCreating(ModelBuilder modelBuilder)
        {
            // Default values
            modelBuilder
                .Entity<TestDef>()
                .Property(e => e.NewInt)
                .HasDefaultValue(5);

            modelBuilder
                .Entity<TestDef>()
                .Property(e => e.NewString)
                .HasDefaultValue("def");

            modelBuilder
                .Entity<TestDef>()
                .Property(e => e.NewBoolTrue)
                .HasDefaultValue(true);

            modelBuilder
                .Entity<TestDef>()
                .Property(e => e.NewBoolFalse)
                .HasDefaultValue(false);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Iva*_*oev 8

这是 EF Core 默认值众所周知的行为/缺陷,因为具有 CLR 默认值的属性(0 表示数字、forfalse等)不会作为插入命令的一部分发送,因此服务器应用配置的默认值。boolDateTime.Empty

在 EFC 5.0 之前,除了不使用数据库默认值之外没有其他解决方案。从 EFC 5.0 开始,解决方法是使用可空支持字段,如使用可空支持字段布尔属性的可空支持字段架构仅默认文档主题中所述(奇怪地隐藏在其他更改跟踪功能部分的使用默认值小节中)。

因此,我们的想法是对此类属性使用可为空的支持字段,例如

private int? _newInt;
[Required]
[Column("NEWINT")]
public int NewInt { get => _newInt ?? 0; set => _newInt = value; }

private bool? _newBoolTrue; 
[Required]
[Column("NEWBOOLTRUE")]
public bool NewBoolTrue { get => _newBool ?? true; set => _newBool = value; }
Run Code Online (Sandbox Code Playgroud)