将父行/子行添加到数据表/数据集+ MySQL数据源

雷耶斯

会员
已加入
2016年11月11日
留言内容
20
编程经验
1-3
大家好

由于存在较大项目的问题,我正在尝试使用MySQL数据库(使用InnoDB引擎)的基本测试,它是:


  1. 在“客户”表中添加新行。
  2. 同时在“订单”表中添加新行。

我正在使用Visual Studio 2017社区中的类型化DataSet进行此操作。我的代码是:

C#:
            DataSet1 ds = new DataSet1();            DataSet1TableAdapters.TableAdapterManager manager = new DataSet1TableAdapters.TableAdapterManager();
            manager.tblCustomersTableAdapter = new DataSet1TableAdapters.tblCustomersTableAdapter();
            manager.tblCustomersTableAdapter.Fill(ds.tblCustomers);
            manager.tblOrdersTableAdapter = new DataSet1TableAdapters.tblOrdersTableAdapter();
            manager.tblOrdersTableAdapter.Fill(ds.tblOrders);


            DataSet1.tblCustomersRow custRow = ds.tblCustomers.NewtblCustomersRow();
            custRow.Name = "Berty";


            ds.tblCustomers.Rows.Add(custRow);


            DataSet1.tblOrdersRow ordersRow = ds.tblOrders.NewtblOrdersRow();
            ordersRow.CustomerID = custRow.CustomerID;


            ds.tblOrders.Rows.Add(ordersRow);


            manager.UpdateAll(ds);

我的错误是:

MySql.Data.MySqlClient.MySqlException:'无法添加或更新子行:外键约束失败(`dbTest`.tblOrders,CONSTRAINT FK_Orders_Customers外键(CustomerID))参考tblCustomers(CustomerID) )在删除级联时在更新级联上)'

MySQL中的关系设置为“ On Update CASCADE”和“ On Delete CASCADE”,如下所示:

MySQL.png


使用SQL Server,这种方法(将PK的ID分配给FK的ID是可行的),那么这是MySQL的事情吗?
 

金西尼

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
3,502
地点
悉尼,澳大利亚
编程经验
10+
数据库是否自动生成PK值?如果是这样,那么丢失的部分可能是将父表的PK值重新返回到DataSet中和/或将这些值传播到子DataTable中。如果您使用的是SQL Server,则表适配器的InsertCommand中的SQL将如下所示:
C#:
INSERT INTO SomeTable(Column1, Column2) VALUES (@Column1, @Column2);
SELECT ID = SCOPE_IDENTITY()
当您向父数据表添加一行时,它将生成一个临时ID,然后您将在子数据表中使用该ID。保存父数据时,数据库将生成最终ID。使用SCOPE_IDENTITY函数检索该值,并将其拉回到父DataTable中。您还需要将DataSet中的DataRelation也设置为在更新时级联,以便将该父ID值传播到子DataTable,以准备保存到数据库。

如果数据库正在生成最终的PK值,则使用MySQL时的情况基本相同,但是您需要找到与SCOPE_IDENTITY等效的MySQL。
 

雷耶斯

会员
已加入
2016年11月11日
留言内容
20
编程经验
1-3
数据库是否自动生成PK值?如果是这样,那么丢失的部分可能是将父表的PK值重新返回到DataSet中和/或将这些值传播到子DataTable中。如果您使用的是SQL Server,则表适配器的InsertCommand中的SQL将如下所示:
C#:
INSERT INTO SomeTable(Column1, Column2) VALUES (@Column1, @Column2);
SELECT ID = SCOPE_IDENTITY()
当您向父数据表添加一行时,它将生成一个临时ID,然后您将在子数据表中使用该ID。保存父数据时,数据库将生成最终ID。使用SCOPE_IDENTITY函数检索该值,并将其拉回到父DataTable中。您还需要将DataSet中的DataRelation也设置为在更新时级联,以便将该父ID值传播到子DataTable,以准备保存到数据库。

如果数据库正在生成最终的PK值,则使用MySQL时的情况基本相同,但是您需要找到与SCOPE_IDENTITY等效的MySQL。

关于插入查询jmcilhinney的最后部分的要点,并感谢您的快速答复。顺便说一句,您继续。刚刚查看了我对数据集的插入查询后,该语句是:INSERT INTO`tblCustomers`(`Name`)VALUES(@ p1)

我只是尝试右键单击表适配器> Configure > Advanced Options >选中“刷新数据表”>行。完成此操作后,Insert语句完全不会更改(Update也不会更改),如果我返回,则不会再次选中它。这似乎是错误的原因(该ID从未得到纠正-它可能仍为'-1','-2'等,等等。

您是否同意我的选择是尝试追加等效的SCOPE_IDENTITY,如果失败,则放弃表适配器,转而使用带有自建存储过程的数据适配器?如果我不能利用表适配器管理器功能,那么我可以更好地受益于类型化数据集而不必在不使用表适配器时进行拆分-听起来很混乱。

再次感谢。
 

金西尼

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
3,502
地点
悉尼,澳大利亚
编程经验
10+
对类型化的数据集进行一些手动更改没有错。将SELECT自动添加到INSERT是Microsoft为SQL Server构建的工具的一部分,也可以通过这种方式创建MySQL工具。如果不是,那只是手动调整,您就可以开始了。
 

雷耶斯

会员
已加入
2016年11月11日
留言内容
20
编程经验
1-3
好吧,正如您所建议的,我已经尝试了一些调整:

1.添加了MySQL的SCOPE_IDENTITY(),SELECT LAST_INSERT_ID();
2.为每个CRUD操作创建一个存储过程。

仍然没有运气,无论如何都会产生与上述相同的错误。显然,它保持自动生成的“ -1”值。我想知道关于表适配器管理器是否只是不被支持...

查询本身可以工作。我已经在单独的执行中测试了它们(而不是作为表适配器管理器的一部分),并且它们可以工作。

难过!
 

雷耶斯

会员
已加入
2016年11月11日
留言内容
20
编程经验
1-3
好的,这是被调用的代码:

C#:
DataSet1 ds = new DataSet1();            DataSet1TableAdapters.tblCustomersTableAdapter taCust = new DataSet1TableAdapters.tblCustomersTableAdapter();
            DataSet1.tblCustomersRow custRow = ds.tblCustomers.NewtblCustomersRow();
            custRow.Name = "James";


            ds.tblCustomers.Rows.Add(custRow);


            int id = taCust.Update(ds.tblCustomers);

这是数据集可视化器为ds.tblCustomers显示的内容:

sc1.png

这是现在的存储过程:

C#:
CREATE DEFINER=`admin`@`192.168.0.10` PROCEDURE `insertCustomer`(IN p1 VARCHAR(45))
BEGIN


    INSERT INTO tblCustomers (Name) VALUES (p1);
    SELECT LAST_INSERT_ID();


END
 

雷耶斯

会员
已加入
2016年11月11日
留言内容
20
编程经验
1-3
嗯,是的,我看到了... SELECT ID = SCOPE_IDENTITY()

好吧,我在那里很有希望,但是我似乎无法在MySQL Workbench中获得等效的(LAST_INSERT_ID())。我只是在存储过程和数据集中的自动生成的Insert语句中尝试过。

那就是我要发送的内容。但!我尝试将其添加到我的插入语句中:

C#:
	SELECT CustomerID FROM tblCustomers WHERE CustomerID = LAST_INSERT_ID();

而且有效!即使在表适配器管理器中,这也正是我想要的。我确实尝试了更多的速记版本,但无法正常运行,但确实如此。

我喜欢克服挑战-非常感谢您为我指出正确的方向(两次)! :踌躇满志:
 

金西尼

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
3,502
地点
悉尼,澳大利亚
编程经验
10+
你错过了我的观点。这是我的代码:
C#:
SELECT ID = SCOPE_IDENTITY()
这是您的代码:
C#:
SELECT LAST_INSERT_ID()
进一步提示,这是我的代码:
C#:
SELECT [B][U][COLOR="#FF0000"]ID =[/COLOR][/U][/B] SCOPE_IDENTITY()
 

雷耶斯

会员
已加入
2016年11月11日
留言内容
20
编程经验
1-3
不,我知道了,尝试了一下,但没有成功!我在“字段列表”中得到“未知列” ID”。这就是为什么我尝试使用“ CustomerID”(具有相同的东西),然后再尝试在上一篇文章中最终起作用的原因。
 

金西尼

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
3,502
地点
悉尼,澳大利亚
编程经验
10+
我认为我一定是第一次误读了您以前的帖子,因为现在看来这很合理。我想我使用的语法受SQL Server支持,但不受MySQL支持。我不奇怪他们与众不同。很高兴你把事情解决了。
 

雷耶斯

会员
已加入
2016年11月11日
留言内容
20
编程经验
1-3
我认为我一定是第一次误读了您以前的帖子,因为现在看来这很合理。我想我使用的语法受SQL Server支持,但不受MySQL支持。我不奇怪他们与众不同。很高兴你把事情解决了。
没问题您之前的指针使我走上了正确的道路,非常感谢您的帮助!


使用Tapatalk从我的SM-G935F发送
 
最佳 底部