简体   繁体   English

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

[英]Issue with EF Core 5 HasDefaultValue, ef pushes default value when value is set to the .Net type default

I'm having a weird issue using entity framework core to insert records with default values columns.我在使用实体框架核心插入带有默认值列的记录时遇到了一个奇怪的问题。 Is there an other way to get the expected behavior, am I missing something stupid?有没有其他方法可以获得预期的行为,我是否错过了一些愚蠢的事情?

tldr: setting an int property = 0 or bool to true results in the default values being used string.empty for the new string gives an ORA-01400: cannot insert NULL (this seems to be an oracle thing) tldr: 将 int 属性 = 0 或 bool 设置为 true 会导致使用默认值 string.empty 新字符串给出 ORA-01400: cannot insert NULL (这似乎是 oracle 的事情)

Scenario's: using a migration to add the new columns and adding new records results in normal behavior (default values are inserted)场景:使用迁移添加新列并添加新记录导致正常行为(插入默认值)

adding a new record only oldField supplied= OK "ID" : 6, "OLDFIELD" : "ef test 1", "NEWINT" : 5, "NEWSTRING" : "def", "NEWBOOLFALSE" : 0, "NEWBOOLTRUE" : 1添加一条新记录只提供 oldField = OK "ID" : 6, "OLDFIELD" : "ef test 1", "NEWINT" : 5, "NEWSTRING" : "def", "NEWBOOLFALSE" : 0, "NEWBOOLTRUE" : 1

adding with a value different than .Net default works too "ID" : 12, "OLDFIELD" : "ef test all set", "NEWINT" : 42, "NEWSTRING" : "string here", "NEWBOOLFALSE" : 1, "NEWBOOLTRUE" : 1添加与 .Net 默认值不同的值也有效"ID" : 12, "OLDFIELD" : "ef test all set", "NEWINT" : 42, "NEWSTRING" : "string here", "NEWBOOLFALSE" : 1, "NEWBOOLTRUE" : 1

Now the problems when you specify 0 for an int and false for the bools现在,当您为 int 指定 0 并为 bool 指定 false 时的问题

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

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

NewString = string.Empty gives an oracle exception ORA-01400: cannot insert NULL (this seems to be an oracle thing) NewString = string.Empty 给出 oracle 异常 ORA-01400: cannot insert NULL (这似乎是 oracle 的事情)

insert query works normally插入查询正常工作

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

This makes it impossible to insert a false value in NEWBOOLTRUE or a 0 in NEWINT without doing an update这使得在不进行更新的情况下无法在 NEWBOOLTRUE 中插入假值或在 NEWINT 中插入 0

testclass (the DbContext OnModelCreating calls TestDef.OnModelCreating(modelBuilder)):测试类(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);
        }
    }
}

This is well known behavior/defect of EF Core default values, since properties with CLR default (0 for numerics, false for bool , DateTime.Empty etc.) are not send as part of the insert command, hence the server applies the configured default value.这是 EF Core 默认值的众所周知的行为/缺陷,因为具有 CLR 默认值的属性(0 表示数字, false表示boolDateTime.Empty等)不会作为插入命令的一部分发送,因此服务器应用配置的默认值价值。

Before EFC 5.0 there was not solution other than not using database default values.在 EFC 5.0 之前,除了不使用数据库默认值之外,没有其他解决方案。 Starting with EFC 5.0, the workaround is to use nullable backing fields as explained in Using nullable backing fields , Nullable backing fields for bool properties and Schema defaults only documentation topics (strangely hidden inside Working with default values subsection of Additional Change Tracking Features section).从 EFC 5.0 开始,解决方法是使用可空支持字段,如使用可空支持字段布尔属性的可空支持字段仅模式默认值文档主题(奇怪地隐藏在使用其他更改跟踪功能部分的默认值小节中)中所述。

So the idea is to use nullable backing field for such properties, eg所以这个想法是为这些属性使用可为空的支持字段,例如

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; }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM