我有一个导入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)中。

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

有没有一种方法可以使上下文在一次验证失败后停止尝试验证对象?我知道我可以等到最后并在结尾处一次调用context.SaveChanges()来解决此问题,但是我希望能够将其与数据库中的哪一行匹配。

作为参考,我使用带有代码优先方法的Entity Framework 6.1。

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

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

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

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

最佳答案

您的问题不是欺骗(这是关于保存而不是加载的实体),但是您可以遵循上述吉米的建议。也就是说,一旦将实体添加到上下文中,就会以“添加”状态对其进行跟踪,阻止其重新验证的唯一方法是通过分离实体。这是一个SO内部链接,但是我将重现代码片段:

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


但是,我不认为这是您要走的路,因为您正在不必要地使用异常来管理状态(众所周知,异常昂贵)。

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


修改您的模型类,使其包含记录原始电子表格行的RowID(可能还有其他充分的理由也可以这样做)
关闭上下文的实体跟踪(更改检测的转弯允许每个Add()为O(1))
添加所有实体
调用context.GetValidationErrors()并使用上述RowID标识无效行,一次获取所有错误。


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



最后,如果您确实想保存好的行并且对基于集合的方法不满意,则最好为每行使用一个新的DbContext,或者至少在每行之后创建一个新的DbContext错误。 ADO.NET团队坚持认为上下文创建“相对便宜”(对不起,我手边没有引用或统计信息),因此这不会对您的吞吐量造成太大影响。即使这样,它将至少保持为O(n)。我不会怪您,管理大环境也可以使您面临其他问题。

10-06 13:23
查看更多