【发布时间】:2021-12-09 20:32:45
【问题描述】:
Postgres 数据库包含带有自然主键的产品表:
create table product
(
productcode char(10) primary key,
price numeric(12,2),
... a lot of other columns
);
以及其他具有自然主键的类似表。
ASP.NET 5 MVC 应用程序用于使用 EF Core 更新它 Npgsql 数据提供者。
如果产品代码也被更改,EF Core 会抛出错误
“Product.Productcode”属性是键的一部分,因此不能修改或标记为已修改。要使用标识外键更改现有实体的主体,首先删除依赖项并调用“SaveChanges”,然后将依赖项与新主体关联。
产品代码在其他表中用作外键(带有 ON UPDATE CASCADE 子句),因此无法删除。
不能更改数据库结构。
如何也允许更新主键列?
一些想法:
-
在 EF Core 中阻止此检查,例如在更新之前将旧值强制设置为与新值相同。
-
在保存更改之前将主键设置为其他值。
-
强制 EF Core 创建更新语句并手动执行
-
使用一些 EF Core 扩展或其他框架。
-
更改 Npgsql EF 核心提供程序以允许这样做。
在不改变数据库结构的情况下实现这一点的最佳方法是什么?
异常抛出
private static void ThrowIfKeyChanged(InternalEntityEntry entry, IProperty property)
{
if (property.IsKey()
&& property.GetAfterSaveBehavior() == PropertySaveBehavior.Throw)
{
throw new InvalidOperationException(CoreStrings.KeyReadOnly(property.Name, entry.EntityType.DisplayName()));
}
}
是否可以将其注释掉并编译新的 EF Core dll。
【问题讨论】:
-
选项 #6:停止更新主键 - 这通常表明设计非常糟糕 - PK应该是稳定且不可变的
-
用户想要更改产品代码。业务逻辑需要它。这不能禁用。
-
那么糟糕的数据库设计选择。可更新的 PK 有异味。是的,许多数据库都支持它(主要是出于历史原因),但它不适合 EF Core 更改跟踪/实体身份系统,因此不受支持。换句话说,你不会从 EF Core 获得帮助。
-
有时用户希望将两个产品合并为一个产品。如何在 EF Core 中实现这一点:可以用新的产品 ID 自动替换所有外键,或者应该使用手动 sql 语句。
-
如上所述,更新 PK 意味着您选择的密钥/关于密钥稳定性的假设失败。解决方案是引入一个新的surrogate PK(可能小于当前的 12 个字节)并在所有外键中进行改进。然后 Productcode 应该是唯一的键约束/索引。这显然是一个相当大的设计更改,但这是假设自然键存在的代价。
标签: c# entity-framework asp.net-core entity-framework-core npgsql