【问题标题】:Does DbContext.SaveChanges() insert new records in the order they were added to DbSet?DbContext.SaveChanges() 是否按照添加到 DbSet 的顺序插入新记录?
【发布时间】:2012-03-25 19:52:28
【问题描述】:

我的问题假设简单插入到没有相关关系的表中。

// various unrelated operations w/context...
var one = new DbRecord();
var two = new DbRecord();
var thr = new DbRecord();
context.DbRecords.Add(one);
context.DbRecords.Add(two);
context.DbRecords.Add(thr);
// various unrelated operations w/context...
context.SaveChanges();

在这种情况下,我的 DbRecord 实体总是会按照我将它们添加到 DbSet 的顺序插入吗?他们似乎在我的测试中,但我可以依赖这个吗?

“各种不相关的操作”是指对同一上下文的不同的、不相关的 DbSet 上的操作;插入、删除和更新实体(在我的例子中是 POCO)

我希望它们以准确的顺序插入,以便我可以使用 pk/identity 字段进行排序,但我还需要利用上下文围绕我的 context.SaveChanges() 提供的隐式事务。尽管就数据库架构而言,其他操作不相关,但条目本身本质上是有关正在执行的更新的日志条目,它们的顺序很关键。

如果上下文不能保证以相同的顺序插入记录,我将不得不在记录中添加一个日期时间字段,并自己处理回滚。

【问题讨论】:

  • 为什么?数据库本身没有“插入顺序”之类的东西......在查询中使用 ORDER BY。
  • @Henk 我可能最终会使用日期时间字段并对其进行排序。尝试查看是否可以按身份/pk 字段排序。
  • @Henk:数据库当然有插入顺序的概念。当您有一个标识列时,该列的值本质上是插入的顺序。然后,您可以按该列排序,并按插入顺序接收记录。
  • @AndrewBarber 这个链接social.msdn.microsoft.com/Forums/en-US/… 似乎表明它们没有按确切的顺序插入
  • @AndrewBarber 还看到了 2009 年 EF 的 Alex James 项目经理的回答,他说他们不保留订单stackoverflow.com/questions/921442/…

标签: c# entity-framework dbcontext entity-framework-4.3


【解决方案1】:

根据文档不能保证这一点。这意味着,您不能依赖此行为。基本上,它归结为您是否愿意承担风险的问题......

  • ...您的寻呼机在半夜响了?
  • ...您发现,运行一年后,这些记录中有 10% 已损坏,无法追溯修复?

回答这些问题由您决定。通常,答案应该是“不”。

如果您的测试正常,这并不意味着您所说的“不相关的操作”在极少数情况下不会造成任何干扰。这是一个无声的错误,在测试期间没有人会注意到。

【讨论】:

  • 这正是我所关心的。我建立了数据库,最初计划在上下文之外向该表添加记录,但最终使用上下文来帮助我做到这一点会变得更加容易。所以,看起来日期时间字段是有序的! +1
  • 当然,您也可以在添加每个日志记录后执行 SaveChanges(并将所有内容包装在事务中,使其仍然是原子的)。或者您可以使用 ExecuteCommand 立即插入。
  • 我可以通过测试确认,当我执行 SaveChanges() 时,以特定顺序添加的元素没有按该顺序保存。无法保证订单。我最终在每次插入后进行了保存,现在它的行为符合预期(但显然更慢)。
【解决方案2】:

我认为它的插入顺序与添加的顺序不同,因为我似乎找不到任何证实这一点的相关信息。另一方面,我相信这会有所帮助,至少我希望如此。 =)

How to observe the Add action of DbSet?

虽然添加 DateTime 字段可能更容易,但这种方法看起来很有趣,因为您似乎想要完成。它建议您订阅 Add 操作并为自己设置顺序,这样您就可以确保它会按照您的意愿插入。

希望这会有所帮助! =)

【讨论】:

  • 实际上,这可能值得研究。尽管对于我的情况来说,日期时间字段可能更容易。 +1 表示“不要假设,因为它没有这么说”和这个想法!
【解决方案3】:

在您的情况下是否可以使用显式事务?我的意思是我会这样做:

using (TransactionScope transaction = new TransactionScope()){
  var one = new DbRecord();
  var two = new DbRecord();
  var thr = new DbRecord();
  context.DbRecords.Add(one);
  context.SaveChanges();
  context.DbRecords.Add(two);
  context.SaveChanges();
  context.DbRecords.Add(thr);
  context.SaveChanges();
  // various unrelated operations w/context...
  context.SaveChanges();
  transaction.Complete();
}

【讨论】:

  • 这是可能的,是的......但它比简单地向表中添加日期时间字段要复杂得多。问题是,我需要在特定事务中包含一些其他各种操作,这意味着更复杂的事务代码。
  • 我认为您不需要具有类似解决方案的额外日期时间字段。实际上,使用这样的显式事务的目的是保证身份的顺序。我不明白你为什么需要复杂的交易代码。我看不出 (TransactionScope transaction = new TransactionScope()){ doSumeDbRelatedStuff1(); 之间有任何区别context.SaveChanges(); doSumeDbRelatedStuff2(); context.SaveChanges();交易。完成();和另一个没有显式事务的版本:doSumeDbRelatedStuff1(); doSumeDbRelatedStuff2(); context.SaveChanges();
  • 一开始我其实有点误解了你的建议。交易代码实际上并不复杂,但更新代码会有点复杂。我想我可以将 Context 的生命周期封装在一个事务中,然后调用我的存储库的 Save() 方法来提交它。
【解决方案4】:

如果您只添加行,您可以让 pk 递增,在这种情况下,您可以相信这些行的顺序正确。如果你真的想要最后一次编辑的时间,尽管你应该使用你所说的 datetime 列。但是,总的来说,如果您想详细说明您正在处理的真正问题,您可以以更简单和干净的方式完成所有操作。

【讨论】:

  • 你是对的;我将添加一个日期时间字段以确保正确排序。虽然我确实分配了增量 pk 值,但问题是我不相信我可以依靠 EF 以我告诉它的相同顺序插入记录。
  • 增量 pk 将被分配得恰到好处,保证。编辑:可能取决于数据库?你用什么做数据库?
  • 我知道增量 PK 将根据 SQL INSERT 语句进入的顺序正确分配。但不能保证的是 Entity Framework 会按照我调用 DbSet.Add(); 的顺序发出这些 INSERT 语句;
  • 它将 pk 标识为增量,因此插入顺序至关重要。有用。编辑:但同样,它不像 MS Access 之类的,对吧?
  • 你指的“它”是什么?英孚?您有此类声明的链接吗?我没有看到这样的文档表明这是定义的行为,保证会发生。是的 - 在我所有的测试中,它们都是按顺序插入的。但是缺乏保证这就是它的完成方式的文档,只是假设是愚蠢的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-01
  • 2015-11-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多