EFCore HasDefaultValueSql (续2 HasComputedColumnSql)

ops/2025/1/11 9:37:03/

前情:EFCore HasDefaultValueSql

EFCore HasDefaultValueSql (续1 ValueGeneratedOnAdd)-CSDN博客

小伙伴在使用 HasDefaultValueSql 时,对相关的 ValueGeneratedOnAdd, HasComputedColumnSql  也有了疑问:

HasComputedColumnSql  

对于计算列,无论是插入还是编辑,应该由数据库的 SCHEMA 上的计算逻辑负责。对于这种场景,ValueGeneratedOnAdd 并不适合,因为它只针对在插入时生成的值,而计算列可能涉及插入和更新两个阶段的行为。

EF Core 中,针对计算列的正确配置应该是使用 ValueGeneratedOnAddOrUpdateHasComputedColumnSql,以下是详细说明。


1. HasComputedColumnSql

HasComputedColumnSql 是用于配置 计算列 的 Fluent API,告诉 EF Core 该列的值是由数据库根据 SQL 逻辑自动计算的。

核心特点
  • 专用于计算列:用于设置数据库的 GENERATED ALWAYS AS 或等效功能。
  • 插入和更新行为:EF Core 不会尝试在插入或更新中显式写入该列的值,而是完全依赖数据库的计算逻辑。
  • 适用场景
    • 表达式列(如计算两个字段的总和)。
    • 基于函数、触发器等逻辑动态生成值的列。
使用示例

假设数据库有一个计算列 TotalPrice,定义为 Price * Quantity

数据库表定义:

CREATE TABLE Orders ( Id INT PRIMARY KEY, Price DECIMAL(10, 2), Quantity INT, TotalPrice AS Price * Quantity PERSISTED 
); 

EF Core 配置:

protected override void OnModelCreating(ModelBuilder modelBuilder) 
{ modelBuilder.Entity<Order>() .Property(o => o.TotalPrice) .HasComputedColumnSql("[Price] * [Quantity]", stored: true); 
} 

解释:

  • [Price] * [Quantity] 是计算逻辑。
  • stored: true 表示这是一个 持久化计算列PERSISTED),结果会存储在数据库中。如果是非持久化列,则省略 stored: true
插入和更新行为
  • 插入时,INSERT 语句中不会包含 TotalPrice
  • 更新时,UPDATE 语句中也不会包含 TotalPrice
  • 示例生成的 SQL:
    INSERT INTO Orders (Price, Quantity) VALUES (10.00, 2); 

2. ValueGeneratedOnAddOrUpdate

ValueGeneratedOnAddOrUpdate 表示字段的值可以在 插入更新 时由数据库生成。这在某些场景下也适用于计算列,但通常需要结合 HasComputedColumnSql 使用。

核心特点
  • 同时覆盖 插入更新 的场景。
  • 不会显式插入或更新字段,EF Core 会假定该字段的值由数据库生成。
使用场景

如果 EF Core 的 HasComputedColumnSql 不适用(如动态触发器逻辑),可以单独使用 ValueGeneratedOnAddOrUpdate

示例配置:

protected override void OnModelCreating(ModelBuilder modelBuilder) 
{ modelBuilder.Entity<Order>() .Property(o => o.TotalPrice) .ValueGeneratedOnAddOrUpdate(); 
} 

此时,TotalPrice 的计算完全依赖数据库逻辑,EF Core 只会在需要时从数据库中重新加载值。


对比和选择

特性HasComputedColumnSqlValueGeneratedOnAddOrUpdate
核心用途显式配置计算列的 SQL 表达式。泛化的生成策略,适用于动态生成值的场景。
插入行为不会包含该列,依赖数据库计算。不会包含该列,依赖数据库生成。
更新行为不会包含该列,依赖数据库计算。不会包含该列,依赖数据库更新或触发器生成。
适用场景数据库定义了明确的计算逻辑(如表达式列)。动态值生成逻辑,如触发器或非表达式列。

总结

  • 如果字段是严格意义上的 计算列,应使用 HasComputedColumnSql
  • 如果字段依赖动态触发器逻辑,但没有明确的计算公式,考虑使用 ValueGeneratedOnAddOrUpdate
  • 通常情况下,HasComputedColumnSql 是计算列的首选方式,因为它与数据库 SCHEMA 定义直接对应,行为明确且易于维护。

补充,mysql的计算列文档:MySQL :: MySQL 8.4 Reference Manual :: 15.1.20.8 CREATE TABLE and Generated Columns





http://www.ppmy.cn/ops/149128.html

相关文章

[IoT]详细设计:智能农业监控系统

以下是基于IoT的智能农业监控系统网络拓扑的详细设计&#xff1a; 网络拓扑详细设计 1. 星型与网状混合拓扑 中心节点&#xff1a;本地服务器或集中控制器作为中心节点&#xff0c;负责协调和管理整个网络。传感器/执行器节点&#xff1a;分布在农田中&#xff0c;负责数据采…

【ROS2】☆ launch之Python

☆重点 ROS1和ROS2其中一个很大区别之一就是launch的编写方式。在ROS1中采用xml格式编写launch&#xff0c;而ROS2保留了XML 格式launch&#xff0c;还另外引入了Python和YAML 编写方式。选择哪种编写取决于每位开发人员的爱好&#xff0c;但是ROS2官方推荐使用Python方式编写…

定时器类QTimer的简单使用

定时器类QTimer 使用流程&#xff1a; 创建一个QTimer类对象后&#xff0c;设置定时器的周期时间间隔setInterval() 然后调用其 start() 函数开启定时器 此后QTimer对象就会周期性的发出 timeout() 信号。 //[1]创建定时器 QTimer timer new QTimer(this); //[2]绑定信号槽函…

Flutter pubspec.yaml 使用方式

Flutter pubspec.yaml 使用方式 pubspec.yaml 是 Flutter 项目中最重要的配置文件之一&#xff0c;用于管理应用的基本信息、依赖项、资源以及构建配置等内容。 1. 基本结构和字段 基本信息 name: my_flutter_app # 应用的名称 description: A new Flutter project …

Allure 集成 pytest

Allure 是一个强大的测试报告工具&#xff0c;与 pytest 集成可以生成详细的测试报告&#xff0c;包括测试步骤、测试数据、截图、错误堆栈等。 1. 安装 Allure 和相关依赖 安装 pytest-allure-adaptor 插件&#xff1a; pip install allure-pytest确保本地已安装 Allure 工具。…

poi-tl+kkviewfile实现生成pdf业务报告

需求背景&#xff0c;需要把ai生成的一些业务数据&#xff0c;生成一份pdf报告 需求分析 简单来说&#xff0c;就是json生成pdf的方案。 直接生成pdf。适合一些pdf样式简单的场景&#xff0c;一般就是纯文本按序渲染&#xff0c;或者是纯表格。如果需要一些复杂的排布&#x…

Java 基于微信小程序的高校科研团队管理系统设计与实现(附源码,部署,文档

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

关于TCP/IP五层结构的理解

关于TCP/IP五层结构的理解 TCP/IP五层模型 是目前被广泛采用的一种模型,我们可以将 TCP / IP 模型看作是 OSI 七层模型的精简版本&#xff0c;由以下 5 层组成&#xff1a; 1. 应用层&#xff1a;应用层是体系结构中的最高层&#xff0c;定义了应用进程间通信和交互的规则。本…