3

我有一个导入 Excel Spreadhseet 并将数据解析到我的数据对象中的过程。这些数据的来源非常值得怀疑,因为我们正在将我们的客户从基于电子表格的数据管理转移到一个可检查有效数据的托管数据库系统中。

在我的导入过程中,我对数据进行了一些基本的完整性检查,以适应我们正在导入的数据可能有多糟糕,但我在 DbContext 中完成了我的整体验证。

我正在尝试做的部分事情是我想在电子表格中提供数据错误的行#,以便他们可以轻松确定需要修复什么来导入文件。

model一旦我从电子表格opp

foreach (var model in Spreadsheet.Rows) { // Again, pseudocode
    if(opp != null && ValidateModel(model, opp, row)) {
        // Copy properties to the database object

        // This is in a Repository-layer method, not directly in my import process.
        // Just written here for clarity instead of several nested method calls.
        context.SaveChanges(); 
    }
}

如果需要,我可以在此处提供更多代码,但问题出在我的 DbContext 的ValidateEntity()方法(覆盖 DbContext)中。

同样,据我所知,我编写的代码没有任何问题,但是如果 Opportunity 未能通过此级别的验证,那么它将保留为 中未保存对象的一部分context,这意味着它会反复尝试每次ValidateEntity()调用时都得到验证。这导致在初始问题发生后,每一行都重复相同的验证错误消息。

有没有办法[编辑]让上下文在验证失败后停止尝试验证对象[编辑]?我知道我可以等到最后并在最后调用context.SaveChanges()一次来解决这个问题,但我希望能够将它与数据库中的行匹配。

作为参考,我使用 Entity Framework 6.1 和 Code First 方法。

编辑试图进一步澄清 Marc L.(包括对上面代码块的更新)

现在,我的流程将遍历电子表格中的行数。我使用每个要保存的对象调用我的存储库层,而不是使用只调用context.SaveChanges()一次的方法的原因是让自己能够确定哪一行是导致验证错误的行。

我很高兴我的 DbContext 的自定义ValidateEntity()方法正在捕获验证错误,但问题在于它没有DbEntityValidationException多次为同一个实体抛出错误。

我希望这样,如果对象验证失败一次,上下文不再尝试保存对象,无论context.SaveChanges()调用多少次。

4

1 回答 1

1

您的问题不是骗人的(这是关于保存,而不是加载实体),但您可以按照上面 Jimmy 的建议进行操作。也就是说,一旦一个实体被添加到上下文中,它就会在“添加”状态下被跟踪,阻止它重新验证的唯一方法是分离它。这是一个 SO 内部链接,但我将重现代码片段:

dbContext.Entry(entity).State = EntityState.Detached;

但是,我认为这不是您想要的方式,因为您正在使用异常来不必要地管理状态(异常是出了名的昂贵)。

根据给出的信息,我会使用更基于集合的解决方案:

  • 修改您的模型类,使其包含记录原始电子表格行的 RowID(也可能有其他充分的理由)
  • 关闭上下文的实体跟踪(变化检测允许每个Add()为 O(1))
  • 添加所有实体
  • 调用context.GetValidationErrors()并立即获取所有错误,使用前面提到的 RowID 来识别无效行。

您没有指出您的进程是应该保存好行还是拒绝整个文件,但这将适应任何一个 - 也就是说,如果您需要保存好行,请使用上面的代码分离所有无效行和然后SaveChanges()


最后,如果您确实想保存好的行并且您对基于集合的方法感到不舒服,那么最好DbContext为每一行使用一个新行,或者至少DbContext在每个错误之后创建一个新行。ADO.NET 团队坚持认为上下文创建是“相对便宜的”(抱歉,我手头没有引用或统计数据),所以这不会对您的吞吐量造成太大损害。即便如此,它至少会保持 O(n)。我不会责怪你,管理一个大的上下文也可以让你面对其他问题。

于 2014-06-03T05:31:57.137 回答