Many-to-many 使用 Entity Framework 和 SQL 服务器插入

Many-to-many inserts with Entity Framework and SQL Server

在我们的数据库中,我们有这个 parent - child - grandchild 关系,即 many-to-many 关系(两次)。这通过两个连接点 / cross-reference tables 发生。 Parent/Child/Grandschild tables 具有唯一的 varchar 功能键。以下是仅显示层次结构中第一步的简化版本:

Parent              Junction             Child
+----+-------+      +------+------+      +----+-------+
| PK | F_KEY |      | PK_1 | PK_2 |      | PK | F_KEY |
+----+-------+      +------+------+      +----+-------+
|  1 | AAA   |      |    1 |    1 |      |  1 | BBB   |
+----+-------+      +------+------+      +----+-------+

parent / child / grandchild 的记录数都是数百万。

情况

我们需要处理这样的情况:我们得到了 parent-child-grandchild 的集合,其中一些可能已经存在于数据库中。我们需要插入那些还不存在的,忽略其余的(基于功能键)。

所以当前的实现:

  1. 关闭 autodetectChanges 并禁用对数据上下文的所有约束。
  2. 检查已经存在的 parent(使用 F_KEY)- 插入不存在的
  3. 检查 children 已经存在 ( F_KEY ) - 插入不存在的并且我认为手动更新 EF
  4. 同上大child仁

不足为奇 - 出了点问题,现在我们的联结点缺少链接 table,我们必须通过脚本解决这个问题。

我不喜欢这个实现。开发人员的论点是性能。原始实现未执行:

  1. 给定的 parent 列表 - 忽略现有列表
  2. 查看剩余 children - 将现有的替换为 DbEntries
  3. 同上child仁
  4. 保存更改()

没有执行。我的同事说——‘想一想:你必须输入 parents,然后检索 ID。保存 children,检索 ID,将这些用于第一个交汇点 table 等。'

问题

我怎样才能让它发挥作用?我的意思是 - 它可以工作,但不是很容易维护,而且确实让我感到不快。

我的一个想法 - 如果我们让连接点 table 包含像这样的独特功能键:

Parent              Junction             Child
+----+-------+      +------+------+      +----+-------+
| PK | F_KEY |      | PK_1 | PK_2 |      | PK | F_KEY |
+----+-------+      +------+------+      +----+-------+
|  1 | AAA   |      |  AAA |  BBB |      |  1 | BBB   |
+----+-------+      +------+------+      +----+-------+

这样我们就不必检索插入项目的 ID 来将它们存储在联结 table 中。那有意义吗? EF 能否从中受益?

如果这不起作用——而且我们没有以其最佳方式使用 EF——我们不妨考虑使用存储过程或直接查询数据库。你完全节省了 EF 的开销,至少你可以完全控制我们正在做的事情,而不是让 EF 在幕后为我们进行查询。

对此有何看法?当然也欢迎任何其他建议。

对于这种任务,我将创建一个存储过程,它接受一些 table 值的参数 https://msdn.microsoft.com/en-us/library/bb510489.aspx https://msdn.microsoft.com/en-us/library/bb675163(v=vs.110).aspx 以及新的 ParentsChildrenJunctionsGrandChildrenJunctions 并在一个事务内在服务器上执行所有合并,而不将任何内容传输回客户端。

一堆 MERGE T-SQL 批量处理行的语句在类似情况下对我来说效果很好。

合并 Parents,然后 Children,然后 GrandChildren table。然后 JunctionParentsChildren 之间。然后 JunctionChildrenGrandChildren 之间。

只要您需要合并的集合大小合理(例如,大约 10K 行),只需调用一次存储过程就可以很好地工作。如果您必须合并更多的行,请考虑将它们分成更小的批次并多次调用您的存储过程。