Bootstrap

EFCore HasDefaultValueSql (续2 HasComputedColumnSql)

前情: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




;