[学习笔记]解决因C#8.0的语言特性导致EFCore实体类型映射的错误

这篇具有很好参考价值的文章主要介绍了[学习笔记]解决因C#8.0的语言特性导致EFCore实体类型映射的错误。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

今天下午在排查一个EF问题时,遇到了个很隐蔽的坑,特此记录。

问题

使用ef执行Insert对象到某表时报错,此对象的Address为空:

 不能将值 NULL 插入列 'Address',表 'dbo.xxx';列不允许有 Null 值。INSERT 失败。

检查数据库和迁移文件时发现Address这个字段被意外设置成nullable: false,而其它的字段却正常,按理来说对于string类型的属性,EFCore在codefirst模式下应该映射为可空类型。

代码也确认了实体中不包含[Required]注释,在任何地方也没有出现.IsRequired()的调用。

于是开始排查:手动创建一个空程序集,引用EFCore,从原项目拷贝EF设计时库、DbContext和各实体类,一顿操作后竟然发现在新的程序集中生成的迁移文件是符合预期的。
令人费解,在多次比对代码之后,发现是.csproj文件中的这一行配置导致的

<Nullable>enable</Nullable>

原因分析

C# 8 引入了一项名为可为 null 引用类型 (NRT) 的新功能。官方文档
该功能允许对引用类型进行批注,指示引用类型能否包含 null。

通过查看EF文档了解到,可为空引用类型通过以下方式影响 EF Core 的行为:

  • 如果禁用可为空引用类型,则按约定将具有 .NET 引用类型的所有属性配置为可选 (例如 string ) 。
  • 如果启用了可为 null 的引用类型,则基于属性的 .NET 类型的 C# 为 Null 性来配置属性:string? 将配置为可选属性,但 string 将配置为必需属性。

换而言之,启用了该功能后,把原本《引用类型可为空》的这个传统约定,更改称为了《引用类型是否可为空,是通过?语法来表明的》,实体中string类型的属性在C#中作为引用类型,自然而然地受到了这个影响。

果然,在删除了这个功能后,string?的语法将不起作用

[学习笔记]解决因C#8.0的语言特性导致EFCore实体类型映射的错误

解决

关闭此功能,重新生成迁移,更新数据库,问题解决。

后记

语言特性会影响EF实体与表结构映射的约定,官方示例中对于string类型的处理方式也做了说明:

无NRT


public class CustomerWithoutNullableReferenceTypes
{
    public int Id { get; set; }

    [Required] // Data annotations needed to configure as required
    public string FirstName { get; set; }

    [Required]
    public string LastName { get; set; } // Data annotations needed to configure as required

    public string MiddleName { get; set; } // Optional by convention
}

有NRT

public class Customer
{
    public int Id { get; set; }
    public string FirstName { get; set; } // Required by convention
    public string LastName { get; set; } // Required by convention
    public string? MiddleName { get; set; } // Optional by convention

    // Note the following use of constructor binding, which avoids compiled warnings
    // for uninitialized non-nullable properties.
    public Customer(string firstName, string lastName, string? middleName = null)
    {
        FirstName = firstName;
        LastName = lastName;
        MiddleName = middleName;
    }
}

这两种模型的数据库映射是等价的。

之后应留意项目的"NRT"功能是否开启,在解决方案.csproj文件中用如下方式关闭

<Nullable>disable</Nullable>

留意实体类中是否有代码段被标识"NRT"功能开启

#nullable disable

#nullable enable

从 .NET 6 开始,默认情况下会为新项目启用这些功能。原始项目是.NET 5.0升级而来的,所以项目文件中并不会包含Nullable相关的配置。

为了一行bug,好值得的一个下午呢文章来源地址https://www.toymoban.com/news/detail-449382.html

到了这里,关于[学习笔记]解决因C#8.0的语言特性导致EFCore实体类型映射的错误的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • MySQL 8.0新特性之INTERSECT和EXCEPT

    最近几年,MySQL 不断致力于兼容 SQL 标准。例如 MySQL 8.0 中的窗口函数、通用表表达式、检查约束等等。 最新发布的 MySQL 8.0.31 继续对 SQL 语句进行了增强,提供了缺失已久的两个集合操作符:INTERSECT 和 EXCEPT。 交集操作符(INTERSECT) INTERSECT 操作符用于返回两个查询结果中的

    2024年02月15日
    浏览(36)
  • 8.0 新特性 - innodb_ddl_threads

    MySQL 8.0.27 引入了一个新变量来控制 InnoDB 可用于创建(排序和构建)二级索引的最大并行线程数: innodb_ddl_threads 通过调整该参数,可以提升二级索引的创建速度。 1. innodb_ddl_threads 创建二级索引时,在排序和构建阶段,使用线程的个数,一定程度上可以加快索引的创建速度,

    2024年02月08日
    浏览(34)
  • Kotlin特性学习笔记

    2,by修饰变量,实现属性委托 3,operator修饰方法,表示重写操作符 kotlin所有运算操作符: 一元操作符(Unary Operators) +a a.unaryPlus() -a a.unaryMinus() !a a.not() a++ a.inc() 二元操作符(  Binary Operators)

    2024年01月18日
    浏览(44)
  • 【C++学习笔记】对象的特性

    浅拷贝:简单的赋值拷贝操作 深拷贝:在堆区重新申请空间,进行拷贝 利用编译器提供的拷贝构造函数,会做浅拷贝操作;会导致堆区的内存重复释放 ![[Pasted image 20221216213144.png]] 解决方法: 利用深拷贝进行解决。 语法: 构造函数():属性1(值1),属性2(值2),...{} ![[Pasted im

    2023年04月26日
    浏览(27)
  • openGauss学习笔记-51 openGauss 高级特性-列存储

    openGauss支持行列混合存储。行存储是指将表按行存储到硬盘分区上,列存储是指将表按列存储到硬盘分区上。 行、列存储模型各有优劣,建议根据实际情况选择。通常openGauss用于OLTP(联机事务处理)场景的数据库,默认使用行存储,仅对执行复杂查询且数据量大的OLAP(联机

    2024年02月11日
    浏览(73)
  • 学习笔记-静态路由配置有来无回导致无法访问目标IP

    配置拓扑图: 已经在R1、R2、R3相应端口配置了相应IP。 在R2上配置静态路由: 执行tracert 10.0.3.3,可以到达目标IP 执行tracert 10.0.13.3,可以到达目标IP 执行tracert 10.0.13.1,无法到达R1的gi0/0/0 display ip routing-table查看R2上的路由表: 可以看到有到10.0.13.0/24的路由,即数据可以到达

    2024年02月08日
    浏览(38)
  • 【字节跳动青训营】后端笔记整理-1 | Go语言入门指南:基础语法和常用特性解析

    **本人是第六届字节跳动青训营(后端组)的成员。本文由博主本人整理自该营的日常学习实践,首发于稀土掘金:🔗Go语言入门指南:基础语法和常用特性解析 | 青训营 本文主要梳理自 第六届字节跳动青训营(后端组)-Go语言原理与实践第一节(王克纯老师主讲) 。同时

    2024年02月13日
    浏览(55)
  • 前端框架学习-ES6新特性(尚硅谷web笔记)

    ECMASript 是由 Ecma 国际通过 ECMA-262 标准化的脚本程序设计语言。javaScript也是该规范的一种实现。 笔记出处:b站 尚硅谷Web前端ES6教程,涵盖ES6-ES11 阮一峰大佬的:ECMAScript 6 入门 ES6 let 使用let声明变量的特点: 不允许重复声 块儿级别作用域 不存在变量提升 不影

    2024年02月12日
    浏览(34)
  • openGauss学习笔记-55 openGauss 高级特性-全密态数据库

    全密态数据库意在解决数据全生命周期的隐私保护问题,使得系统无论在何种业务场景和环境下,数据在传输、运算以及存储的各个环节始终都处于密文状态。当数据拥有者在客户端完成数据加密并发送给服务端后,在攻击者借助系统脆弱点窃取用户数据的状态下仍然无法获

    2024年02月10日
    浏览(43)
  • java中实体pojo对于布尔类型属性命名尽量别以is开头,否则 fastjson可能会导致属性读取不到

    假如我们有一个场景,就是需要将一个对象以字符串的形式,也就是jsonString存到一个地方,比如mysql,或者redis的String结构。现在有一个实体,我们自己创建的,叫做CusPojo.java 有两个属性是布尔类型的,一个属性是有is开头,一个是没有is开头的,我们就可以做个对比。 现在

    2024年02月21日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包