【问题标题】:Cannot add or update a child row: a foreign key constraint fails while doing INSERT in a foreach无法添加或更新子行:在 foreach 中执行 INSERT 时外键约束失败
【发布时间】:2020-06-10 17:16:30
【问题描述】:

尝试在 MySQL db 中添加一些项目时,我收到以下错误:

: '无法添加或更新子行:外键约束失败 (articoli_ordini, CONSTRAINT fk_articoli_ordini_ordini1 FOREIGN KEY (ID_OR_ART) REFERENCES ordini (ID_OR) ON DELETE CASCADE ON UPDATE CASCADE) '

似乎通过LAST_INSERT_ID() 找不到我应该添加到INSERT 查询的外键,但列表的第一项已成功添加,而下一项失败。

我要添加项目的 MySQL 表是 3,Ordini 假设它是父表,Articoli_Ordini 在 ID 为 OrdiniVarianti_Articoli 上有外键,它指的是 Articoli_Ordini 所以有id 为 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() 存储为Articoli_Ordini 甚至Varianti_Articoli 并使用它而不是直接插入LAST_INSERT_ID()

【问题讨论】:

  • 您将存储父级的LAST_INSERT_ID。第二次迭代使用子查询的LAST_INSERT_ID

标签: c# mysql


【解决方案1】:

假设您要插入 3 个内容;一位家长和两个相关的孩子。您添加了父项,您成功添加了第一个子项,因为您将其父项 ID 声明为 LAST_INSERT_ID 并且最近插入的内容是父项,因此 LAST_INSERT_ID 返回的内容是父项的 ID..

但是当您插入 second 孩子时,最近插入的是 first 孩子,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,这样您就只有一个包含两个子对象列表的父对象,然后您只需说出类似 context.Add(myParentWithTwoChildren); context.SaveChanges(); 的内容。这样的软件存在并且会为你节省无数时间浪费的生命,编写重复的插入查询,这些查询是如此的样板,以至于它们可以(并且应该)由代码而不是人类编写

【讨论】:

  • 我不知道 LAST_INSERT_ID() 正在获取最近插入项的 ID,我认为这就像获取引用外键表的最后一个 ID,虽然从未听说过 ORM 但通过现在阅读有关它的东西,它似乎很有趣,一定会尝试使用它!
猜你喜欢
  • 2020-10-04
相关资源
最近更新 更多