我有一个这样的模型:
class Client
{
public int id {get; set;}
...
public DateTime CreatedAt {get; set;}
}
具有以下类型配置(所有其他字段都有默认配置):
builder.Property(p => p.CreatedAt)
.HasDefaultValueSql("now() at time zone 'utc'")
.ValueGeneratedOnAdd() .Metadata.SetAfterSaveBehavior(Microsoft.EntityFrameworkCore.Metadata.PropertySaveBehavior.Ignore);
当我执行更新操作时,我不想提供 CreatedAt 值,即我希望它始终保持不变,因此在我的 API 联系人中,我什至不接受 PUT(更新)端点的 CreatedAt 值。 我想要的是在更新期间忽略 CreatedAt 字段,这就是 Metadata.SetAfter... 的原因。但是,在 SaveChanges() 之后,CreatedAt 字段保持为空/默认值。
我想以某种方式指示 EF Core 在更新操作期间获取 CreatedAt 字段的值,即使我不更新它。有什么办法可以实现吗?
我知道可以使用类似 Reload() 的方法来重新加载所有字段,但这意味着对于 1 个更新操作,应用程序将始终对数据库执行 2 个请求。第二个请求的唯一原因只是为了获取 CreatedAt 字段的值,这对我来说听起来不太好。
插入时将填充 CreatedAt 字段。更新永远不会改变它。正常的更新操作应该从修改后的 DTO/Viewmodel 中获取并更新实体属性,以便您在该时间点获得 CreatedAt。由于这是一个计算属性,因此您应该保护 setter,因为代码永远不能更改 CreatedAt 时间戳:
public DateTime CreatedAt {get; protected set;}
从那里我将删除元数据。 从那里插入新实体后,应在保存后填充 CreatedAt 值。对于更新操作,请避免使用
Update
方法,例如:
var order = new Order { Id = orderId, .... };
_context.Update(order);
_context.SaveChanges();
或更糟糕的是,在控制器操作中,使用从客户端实现的实体来调用
Update()
传递分离的实体。您应该避免这种方法的原因是它可能容易发生数据篡改(以您不期望的方式更改请求并覆盖不应更改的数据),并且 Update()
会为所有(非即使值没有更改,每次也会生成)列。通过使用 EF 的更改跟踪和复制值,您可以获得以下好处:
确保更新行存在且有效。UPDATE
UPDATE
为了帮助避免一次手动复制一个属性,您可以使用 Automapper 或 Mapperly 等映射器来定义执行更新时可以复制的允许映射。 IE。如果只需要编辑 6 个字段,您可以确保只复制这 6 个可能的值。