c# - 无法添加或更新子行:在 foreach 中执行 INSERT 时外键约束失败
问题描述
在尝试在 MySQL db 中添加一些项目时,我收到以下错误:
:'无法添加或更新子行:外键约束失败(
articoli_ordini
,CONSTRAINTfk_articoli_ordini_ordini1
FOREIGN KEY(ID_OR_ART
)REFERENCESordini
(ID_OR
)ON DELETE CASCADE ON UPDATE CASCADE)'
似乎我应该添加到 INSERT 查询的外键没有通过执行找到,LAST_INSERT_ID()
但列表的第一项已成功添加,而下一项失败。
我要添加项目的 MySQL 表是 3,Ordini
假设它是父表,在Articoli_Ordini
id of 上具有外键,Ordini
并且在 id of上具有外键。Varianti_Articoli
Articoli_Ordini
Articoli_Ordini
我正在执行所有 INSERT 的方法如下所示:
var query_ordine = @"INSERT INTO `ordini` (`TIPO_OR`, `ORA_OR`, `SENT_OR`, `ID_OR_CFG`) VALUES (@tipo, NOW(), 0, @cfg);";
using var connection = new MySqlConnection(connectionString);
connection.Open();
using var cmd = new MySqlCommand(query_ordine, connection);
cmd.Parameters.AddWithValue("@tipo", carrello.tipo);
cmd.Parameters.AddWithValue("@cfg", cfg);
cmd.Parameters.AddWithValue("@id", 0);
cmd.Parameters.AddWithValue("@qta", 0);
cmd.Prepare();
try
{
cmd.ExecuteNonQuery();
}
catch (Exception e)
{
return new StatusCodeResult(500);
}
foreach (var articolo in carrello.articoli)
{
var query_articolo = @"INSERT INTO `articoli_ordini` (`TIPO_ART`, `COD_ART`, `QTA_ART`, `ID_OR_ART`) VALUES (@tipo, (SELECT CODICE_PRP FROM vo_plurep WHERE ID_PLUREP = @id), @qta, LAST_INSERT_ID());";
cmd.CommandText = query_articolo;
cmd.Parameters["@tipo"].Value = articolo.tipo;
cmd.Parameters["@id"].Value = articolo.id;
cmd.Parameters["@qta"].Value = articolo.qta;
cmd.ExecuteNonQuery();
foreach(var variante in articolo.varianti)
{
var query_variante = @"INSERT INTO `varianti_articoli` (`COD_VAR`, `ID_ART_VAR`) VALUES ((SELECT CODICE_VAR FROM vo_varianti WHERE ID_VARIANTI = @id), LAST_INSERT_ID());";
cmd.CommandText = query_variante;
cmd.Parameters["@id"].Value = variante.id;
cmd.ExecuteNonQuery();
}
}
并在第二个循环失败foreach (var articolo in carrello.articoli)
我应该先存储LAST_INSERT_ID()
forArticoli_Ordini
甚至 forVarianti_Articoli
并使用它而不是直接插入LAST_INSERT_ID()
?
解决方案
假设您要插入 3 样东西;一位家长和两个相关的孩子。您添加了父级,您成功添加了第一个子级,因为您将其父级 ID 声明为 LAST_INSERT_ID 并且最近插入的东西是父级,所以 LAST_INSERT_ID 返回的东西是父级的 ID。
但是当您插入第二个孩子时,最近插入的是第一个孩子,并且 LAST_INSERT_ID 将更改为告诉最近插入的孩子记录的 ID。如果父母多于孩子,这甚至可能有效,但您最终会将这个孩子与错误的父母联系起来
insert parent -> last_id is parent 1234
insert child1 as child of 1234 -> last_id is child 6667
insert child2 as child of 6667 -> either: works and links child to parent 6667
or: fails (no parent 6667)
所以是的,你应该插入父级,选择它的 LAST_INSERT_ID 并在你的 C# 中检索/存储它,然后为你必须插入的每个子级重用缓存的父级 ID
或者更好的是,使用一个 ORM 来为你做这一切,所以你只有一个 Parent 对象和一个包含两个 Child 对象的列表,你只需说类似context.Add(myParentWithTwoChildren); context.SaveChanges();
. 存在这样的软件并将为您节省无数时间浪费的生命,编写重复的插入查询,这些查询是如此的样板,以至于它们可以(并且应该)由代码而不是人类编写
推荐阅读
- vba - 图表数据标签地狱
- mongodb - 在 CentOS 7 上安装 Mongo 3.6
- java - 将 Java cookie 对象转换为要在 httpResponse“Set-Cookie”标头中设置的字符串
- microsoft-teams - 通过 GPO 为 Microsoft 团队禁用功能
- angular - CdkDropList 上的动态高度问题
- c++ - 数组的两个索引具有相同的内存地址
- reactjs - 为什么访问非
页面清除我的持久性:轮询身份验证? - java - 从 Blender 2.8 导出到 LibGDX
- c# - 即使我以管理员身份运行 Visual Studio,编译时也无法注册程序集
- python - 计算二维实对称矩阵的特征值和特征向量的最快方法是什么