【问题标题】:How do I determine if a record is new or not before adding it to the DbSet在将记录添加到 DbSet 之前如何确定记录是否为新记录
【发布时间】:2021-07-15 15:55:56
【问题描述】:

我有一个准备功能,用于将记录保存到数据库中,这可能有点矫枉过正,但我​​的想法是我可以在以后添加它。

public void Prepare<T>(T model) where T : class {
    var key = ReflectionHelper.GetAttribute<T, KeyAttribute>();
    if(null == key) { return; }

    SetContext<T>();
    var set = DbManager.Context.Set<T>();

    object id = key.GetValue(model);
    object def = key.PropertyType.GetDefaultValue();
    if(id == def) { set.Add(model); }
}

当前的实现只是检查记录的主键是否为默认值(通常为 0),然后将其添加到数据集中。这适用于 90% 的表将使用自动递增键构建的情况,但是,我遇到了一个表的问题,其中键是为每条记录手动生成的,这意味着它是在插入之前设置的进入数据库。

对于上述功能,这显然不理想,它导致检查失败并且实际上没有将其保存到数据库中。我知道实体框架必须进行某种内部测试来检查记录是否是新的,以确定它是否需要执行 UPDATE 或 INSERT 和 AFAIK,它不依赖于预先设置的 ID,否则我会EF 的代码与我使用上述函数时遇到的问题相同。有没有办法可以从该检查中提取结果,而不是我目前正在做的方式?

【问题讨论】:

  • 这就是DbSet.Update 的用途。
  • @GertArnold 不幸的是我没有使用核心:(

标签: c# .net entity-framework


【解决方案1】:

这是通用的“一刀切”方法开始失败的地方。只要实现相同,它们就可以高效地工作。一旦遇到特殊情况,就意味着引入复杂性。

如果键不能反映实体是新的还是现有的(即 0 / null = new),则典型的方法是尝试加载实体以执行更新,否则插入。

var existingEntity = set.SingleOrDefault(x => x.Id == id);
if (existingEntity != null)
{
    Mapper.Map(model, existingEntity);
}
else
{
    existingEntity = set.Add(model);
}

“Upsert”实现可能带来的问题是,应用程序可能会开始意外插入您希望存在的记录,如果它们不存在,则可能应该进行处理。 (过时数据、篡改等)我对系统的建议是明确地使用专用的 Add/Insert 与 Update 方法调用链。

DbSet.Update 也可以用于管理更新或插入方案,但与使用 EF 的更改跟踪器相比,这不是最佳的,因为它会为所有列生成更新 SQL 语句,无论它们是否更改。如果您手动更新所有列或使用 Automapper 的 Map 方法跨值复制,则更改跟踪器只会为更改的列生成一条语句。这也使您可以控制确保在更新方案中只能更改允许的值。例如,UI 只希望更改某些字段,最坏的情况是,如果您从客户端传回完整的实体,当您手动复制或 Automapper 映射仅传输预期的字段值时,模型中的其他值无法被篡改。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-03-06
    • 2015-03-24
    • 2017-03-20
    • 2011-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多