EFCore HasDefaultValueSql

news2025/1/12 14:46:24

今天小伙伴在代码中遇到了有关 HasDefaultValue 的疑问,这里整理澄清下...

在使用 Entity Framework Core (EFCore) 配置实体时,HasDefaultValue 方法会为数据库列设置一个默认值。该默认值的行为取决于以下条件:


1. 配置 HasDefaultValue 的应用场景

HasDefaultValue 主要在以下场景中生效:

  • 首次创建表时:当迁移生成 CREATE TABLE 的 SQL 脚本时,会在列定义中附带默认值。
  • 列被新增到现有表时:在迁移中,新增列时,如果指定了 HasDefaultValue,生成的 SQL 脚本会为新增列设置默认值。

示例:

modelBuilder.Entity<MyEntity>() 
    .Property(e => e.MyColumn) 
    .HasDefaultValue(100); 

2. 默认值的应用条件

1) 创建表

如果使用迁移创建表,HasDefaultValue 会为列添加默认值。例如:

CREATE TABLE MyEntity ( 
    Id INT PRIMARY KEY, 
    MyColumn INT DEFAULT 100 
); 
2) 添加新列

如果表已经存在,且通过迁移为现有表新增列,HasDefaultValue 会生成如下 SQL:

ALTER TABLE MyEntity ADD MyColumn INT DEFAULT 100; 

在添加列时,DEFAULT 值会应用到已存在的行。

3) 插入数据

当应用程序通过 EFCore 插入记录,而未显式为列提供值时:

  • EFCore 会让数据库使用定义的默认值(依赖于数据库执行)。

注意:EFCore 不会在内存中自动填充默认值到实体属性上。


3. 特殊条件下的行为

1) 与 HasDefaultValueSql 的区别
  • HasDefaultValue:直接定义一个常量值。
  • HasDefaultValueSql:允许使用 SQL 表达式设置默认值。

例如:

modelBuilder.Entity<MyEntity>() 
    .Property(e => e.MyColumn) 
    .HasDefaultValueSql("GETDATE()"); 

生成的 SQL:

   ALTER TABLE MyEntity ADD MyColumn DATETIME DEFAULT GETDATE(); 
2) 更新表格时的影响

如果尝试将现有列的默认值修改为另一个值,EFCore 迁移中不会自动生成 ALTER COLUMN SQL,需要手动调整迁移。

3) 在内存中的作用

在运行时,HasDefaultValue 不会对未赋值的属性生效,即在 EFCore 中 HasDefaultValue 仅影响数据库的默认行为。


4. 实际示例与注意事项

代码示例
public class MyEntity 
{ 
    public int Id { get; set; } 
    public int MyColumn { get; set; } 
} 

// 配置 
modelBuilder
    .Entity<MyEntity>() 
    .Property(e => e.MyColumn) 
    .HasDefaultValue(100); 
生成的迁移代码
migrationBuilder.CreateTable( 
    name: "MyEntity",
    columns: table => new 
    { 
        Id = table.Column<int>(nullable: false) 
             .Annotation("SqlServer:Identity", "1, 1"), 
        MyColumn = table.Column<int>(nullable: false, defaultValue: 100) 
    }, 
    constraints: table => 
    { 
        table.PrimaryKey("PK_MyEntity", x => x.Id); 
    }); 
插入数据的行为
  • 如果你执行如下代码:
context.MyEntities.Add(new MyEntity { Id = 1 }); 
context.SaveChanges(); 

结果中 MyColumn 的值会由数据库设置为 100


5. 总结

HasDefaultValue 在以下情况下生效:

  1. 数据库表初次创建时。
  2. 为现有表新增列时。
  3. 插入数据时,如果 EFCore 没有为该列赋值,则数据库会自动使用默认值。

如果你想在代码中为未赋值的属性提供默认值,需额外在 C# 类中定义默认值逻辑。

在使用 Entity Framework Core 创建实体并保存到数据库时,如果你为属性赋值了,即使这个值与 HasDefaultValue 配置的值相同,EFCore 的行为取决于以下几个因素:

1. EFCore 的默认行为

  • 显式赋值的属性: 即使属性的值与 HasDefaultValue 中定义的值相同,EFCore 会将其视为已显式设置。因此,生成的 SQL 插入语句会包含该字段及其值。

示例:

modelBuilder.Entity<MyEntity>() 
    .Property(e => e.MyColumn) 
    .HasDefaultValue(100); 

var entity = new MyEntity 
{ 
    MyColumn = 100 // 显式赋值与默认值相同 
}; 

context.MyEntities.Add(entity);
context.SaveChanges(); 

生成的 SQL 类似如下:

INSERT INTO MyEntity (MyColumn) VALUES (100); 

2. 如何忽略字段

EFCore 只有在属性未显式赋值(即为 null 或默认类型值,如 0 对于整型)时,才会让数据库使用 HasDefaultValue 配置的默认值。

示例:

var entity = new MyEntity(); // 未赋值 
MyColumn context.MyEntities.Add(entity);
context.SaveChanges(); 

生成的 SQL 类似如下:

INSERT INTO MyEntity DEFAULT VALUES; 

如果表的 MyColumn 定义了默认值 100,那么数据库会将其设置为 100


3. 如何避免显式赋值时重复生成字段

如果你希望 EFCore 在插入数据时忽略与默认值相同的显式赋值字段,可以通过以下方式实现:

1) 使用默认值优化器

手动检测属性值是否等于默认值,并在这种情况下将其设置为 null

var entity = new MyEntity 
{ 
    MyColumn = 100 // 与默认值相同 
}; 

if (entity.MyColumn == 100) 
{ 
    entity.MyColumn = default; // 设置为默认值 
}

context.MyEntities.Add(entity); 
context.SaveChanges(); 

生成的 SQL:

INSERT INTO MyEntity DEFAULT VALUES; 
2) 自定义 SaveChanges 拦截器

DbContext.SaveChanges 方法中拦截并移除与默认值相同的字段:

public override int SaveChanges() 
{ 
    foreach (var entry in ChangeTracker.Entries<MyEntity>()) 
    { 
        if (entry.State == EntityState.Added && entry.Entity.MyColumn == 100) 
        {
            entry.Property(e => e.MyColumn).IsModified = false; 
        } 
    } 

    return base.SaveChanges(); 
} 

4. 总结

  1. 如果为属性显式赋值,即使值与 HasDefaultValue 一样,EFCore 会生成包含该字段的 SQL。
  2. 要避免生成重复字段,可以在代码逻辑中手动移除默认值的赋值,或使用自定义拦截器动态处理。
  3. 默认值 (HasDefaultValue) 仅在未赋值或未提供字段时,由数据库自动填充。

补充:

配置字段为数据库生成

protected override void OnModelCreating(ModelBuilder modelBuilder) 
{ 
    modelBuilder.Entity<Example>() 
    .Property(e => e.Age) 
    .HasDefaultValueSql("18");} 

归纳一下:

  1. HasDefaultValueSql("18") 的作用:

    • 它的主要作用是 在模型构建时告诉 EF Core 该字段在数据库中有默认值
    • EF Core 不会强制使用 HasDefaultValueSql 配置的值生成 INSERT 语句,而是让数据库的默认值(DEFAULT 定义)生效。
  2. EF Core 生成 INSERT 的行为:

    • 如果字段没有显式赋值(即在代码中未为该字段赋值),EF Core 不会在生成的 INSERT 语句中包含该字段,从而依赖数据库在 SCHEMA 上的 DEFAULT 值。
    • 如果代码中显式赋值了该字段,即使值与 HasDefaultValueSql 的配置一致,EF Core 仍会在 INSERT 语句中包含该字段,并使用显式赋值的值。
  3. 实际生效的值:

    • 关键是数据库表定义中的 DEFAULT 值(由 CREATE TABLEALTER TABLE 设置)。
    • HasDefaultValueSql 中配置的 SQL 只是 帮助 EF Core 在迁移中设置数据库表的默认值,一旦表的 SCHEMA 定义了默认值,EF Core 就不再干涉。
  4. HasDefaultValueSql 的核心意义:

    • 它是在 数据库迁移时,帮助生成类似如下的 SQL:
      ALTER TABLE Example ADD CONSTRAINT DF_Age DEFAULT 18 FOR Age; 
    • 一旦表的默认值设置完成,EF Core 的 HasDefaultValueSql 配置就不再直接影响运行时行为

示例验证

表定义
CREATE TABLE Example ( Id INT PRIMARY KEY, Name NVARCHAR(50), Age INT DEFAULT 18 ); 
Fluent API 配置
protected override void OnModelCreating(ModelBuilder modelBuilder) 
{
    modelBuilder.Entity<Example>() 
    .Property(e => e.Age) 
    .HasDefaultValueSql("18"); 
} 
插入代码
var example = new Example 
{ 
     Name = "Alice" // Age 未赋值 }; 
     context.Examples.Add(example);
     context.SaveChanges();  
}

生成的 SQL:

INSERT INTO Example (Name) VALUES ('Alice'); -- Age 列未包含 

数据库最终插入:

Id | Name | Age 1 | Alice | 18 
如果数据库默认值改变

假如数据库表的 DEFAULT 定义改为 20,代码和 Fluent API 不变:

生成的 SQL 仍然是:

INSERT INTO Example (Name) VALUES ('Alice'); -- Age 列未包含 

但最终插入的值会变为:

Id | Name | Age 1 | Alice | 20 

这说明 运行时实际生效的是数据库表的 DEFAULT


总结

  • HasDefaultValueSql 的配置值不会直接影响运行时行为,其作用主要是用于迁移时生成表的默认值定义。
  • 最终起作用的是数据库表的默认值,而不是 HasDefaultValueSql 配置中的值。
  • 只要字段未显式赋值,无论是可空还是非可空,EF Core 都会依赖数据库表的默认值生效。



本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2275529.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ECharts饼图下钻

背景 项目上需要对Echarts饼图进行功能定制&#xff0c;实现点击颜色块&#xff0c;下钻显示下一层级占比 说明 饼图实现点击下钻/面包屑返回的功能 实现 数据结构 [{name: a,value: 1,children: [...]},... ]点击下钻 // 为图表绑定点击事件&#xff08;需要在destroy…

Java聊天小程序

拟设计一个基于 Java 技术的局域网在线聊天系统,实现客户端与服务器之间的实时通信。系统分为客户端和服务器端两类,客户端用于发送和接收消息,服务器端负责接收客户端请求并处理消息。客户端通过图形界面提供用户友好的操作界面,服务器端监听多个客户端的连接并管理消息通…

蓝桥杯嵌入式速通(1)

1.工程准备 创建一文件夹存放自己的代码&#xff0c;并在mdk中include上文件夹地址 把所有自身代码的头文件都放在headfile头文件中&#xff0c;之后只需要在新的文件中引用headfile即可 headfile中先提前可加入 #include "stdio.h" #include "string.h"…

net-http-transport 引发的句柄数(协程)泄漏问题

Reference 关于 Golang 中 http.Response.Body 未读取导致连接复用问题的一点研究https://manishrjain.com/must-close-golang-http-responsehttps://www.reddit.com/r/golang/comments/13fphyz/til_go_response_body_must_be_closed_even_if_you/?rdt35002https://medium.co…

TrustRAG:增强RAG系统鲁棒性与可信度的创新框架

在人工智能飞速发展的今天&#xff0c;大语言模型&#xff08;LLMs&#xff09;凭借其强大的语言处理能力在诸多领域大放异彩。检索增强生成&#xff08;RAG&#xff09;系统&#xff08;面向企业RAG&#xff08;Retrieval Augmented Generation&#xff09;系统的多维检索框架…

业务链指标,用户行为模式识别,埋点系统

个人博客&#xff1a;无奈何杨&#xff08;wnhyang&#xff09; 个人语雀&#xff1a;wnhyang 共享语雀&#xff1a;在线知识共享 Github&#xff1a;wnhyang - Overview 此前&#xff0c;我们已经成功搭建起最为基础的聚类指标体系&#xff0c;涵盖计数、求和、最大值、最小…

Git撤销指定commit并更新远端仓库

Git撤销指定commit并更新远端仓库 一、撤销指定commit 1.首先执行git log 命令&#xff0c;查看git历史提交以及commit信息&#xff1a; 由于需要脱敏&#xff0c;所以截图可能看得马赛克比较多&#xff0c;需要关注的就是上面的commit后跟的id&#xff0c;以及HEAD当前指定…

基于DFT与IIR-FIR滤波器的音频分析与噪声处理

基于DFT与IIR-FIR滤波器的音频分析与噪声处理 【完整源码文档报告】 【需要可随时联系博主&#xff0c;常在线能秒回!】 系统功能与实现介绍 功能与实现 音频处理系统界面搭建&#xff1a;利用MATLAB的GUI工具&#xff0c;构建了音频分析界面&#xff0c;包括文件导入、录…

基于单片机的无线气象仪系统设计(论文+源码)

1系统方案设计 如图2.1所示为无线气象仪系统设计框架。系统设计采用STM32单片机作为主控制器&#xff0c;结合DHT11温湿度传感器、光敏传感器、BMP180气压传感器、PR-3000-FS-N01风速传感器实现气象环境的温度、湿度、光照、气压、风速等环境数据的检测&#xff0c;并通过OLED1…

MySQL库表的操作

目录 一、库的操作 1.1库的创建 1.2字符集和校验规则 1.2.1 查看系统默认字符集以及校验规则 1.2.2 查看数据库支持的字符集 1.2.3 查看数据库支持的字符集校验规则 1.2.4 校验规则对数据库的影响 1.3操纵数据库 1.3.1显示库 1.3.2显示创建语句 1.3.3修改数据库 1.3…

硬件设计-齐纳管

目录 摘要 详情 齐纳管的工作电流、 摘要 齐纳管&#xff08;Zener Diode&#xff09;是一种特殊的二极管&#xff0c;它能够在特定的反向电压下保持电流稳定。正常情况下&#xff0c;二极管只允许正向电流通过&#xff0c;而阻止反向电流流过。而齐纳管在一定的反向电压下可…

Airflow:TimeSensor感知时间条件

在数据管道工作流中&#xff0c;任务可能需要在特定的时间执行&#xff0c;或者在继续之前等待一定的时间。为了满足这些需求&#xff0c;Apache Airflow提供了TimeSensor&#xff0c;这是一种内置Sensor&#xff0c;可以监控当前时间&#xff0c;并在达到指定时间时触发后续任…

libusb学习——简单介绍

文章目录 libusb 简介libusb 编译libusb 源码目录介绍核心代码文件平台支持例子 API使用libusb初始化和去初始化libusb设备处理和枚举libusb 杂项libusb USB描述符libusb 设备热插拔事件通知libusb 异步设备I/Olibusb 同步设备I/Olibusb 轮询与定时 libusb 涉及技术参考 libusb…

HTML5 网站模板

HTML5 网站模板 参考 HTML5 Website Templates

阿里云ios镜像源

阿里云镜像源&#xff1a;阿里巴巴开源镜像站-OPSX镜像站-阿里云开发者社区 下载centos7

【大数据】Apache Superset:可视化开源架构

Apache Superset是什么 Apache Superset 是一个开源的现代化数据可视化和数据探索平台&#xff0c;主要用于帮助用户以交互式的方式分析和展示数据。有不少丰富的可视化组件&#xff0c;可以将数据从多种数据源&#xff08;如 SQL 数据库、数据仓库、NoSQL 数据库等&#xff0…

【2024年华为OD机试】 (A卷,100分)- 端口合并(Java JS PythonC/C++)

一、问题描述 题目描述 有 M 个端口组 (1 < M < 10)&#xff0c; 每个端口组是长度为 N 的整数数组 (1 < N < 100)&#xff0c; 如果端口组间存在 2 个及以上不同端口相同&#xff0c;则认为这 2 个端口组互相关联&#xff0c;可以合并。 输入描述 第一行输入端…

【灵码助力安全3】——利用通义灵码辅助智能合约漏洞检测的尝试

前言 随着区块链技术的快速发展&#xff0c;智能合约作为去中心化应用&#xff08;DApps&#xff09;的核心组件&#xff0c;其重要性日益凸显。然而&#xff0c;智能合约的安全问题一直是制约区块链技术广泛应用的关键因素之一。由于智能合约代码一旦部署就难以更改&#xf…

AOP实现操作日志记录

文章目录 1.common-log4j2-starter1.目录2.pom.xml 引入依赖3.LogAspect.java4.Log4j2AutoConfiguration.java Log4j2自动配置类条件注入切面类 2.common-log4j2-starter-demo 测试1.目录2.application.yml 启用日志切面3.TraceController.java4.结果 1.common-log4j2-starter …

分布式ID—雪花算法

背景 现在的服务基本是分布式、微服务形式的&#xff0c;而且大数据量也导致分库分表的产生&#xff0c;对于水平分表就需要保证表中 id 的全局唯一性。 对于 MySQL 而言&#xff0c;一个表中的主键 id 一般使用自增的方式&#xff0c;但是如果进行水平分表之后&#xff0c;多…