如何使用自动生成的标识密钥更新数据集父子表?

Posted

技术标签:

【中文标题】如何使用自动生成的标识密钥更新数据集父子表?【英文标题】:How to update Dataset Parent & Child tables with Autogenerated Identity Key? 【发布时间】:2010-10-30 05:15:21 【问题描述】:

我在我的 VB 应用程序中使用 ADO.NET 数据集。我有一个带有一个父表和许多子表的类型化数据集。我想在将数据插入父表时生成标识密钥,然后使用相同的键(作为外键)更新所有子表中的数据。

最后,我想更新数据库(SQL Server08)中的数据集。

嗯,上面的事情可以通过首先直接在数据库中插入父表,获取标识列,然后用于子表。

但我想将此作为自动操作(如 LINQ to SQL,它负责数据上下文中的主键和外键。)

我在处理父表和子表的自动生成列的数据集中有可能吗?

谢谢,

ABB

【问题讨论】:

【参考方案1】:

我认为这应该更明显,并且无需任何调整即可工作。但是,这仍然很容易。

解决方案分为两部分:

    在子表和父表之间创建DataRelation,并将其设置为更新时级联。 这样,每当父 ID 更改时,所有子 ID 都会更新。

    Dim rel = ds.Relations.Add(parentTab.Columns("Id"), childTab.Columns("ParentId"))
    rel.ChildKeyConstraint.UpdateRule = Rule.Cascade
    

    数据集插入和更新命令是双向的: 如果绑定了任何输出参数或返回了任何数据行, 它们将用于更新导致更新的数据集行。

    这对于这个特定问题最有用:获取自动生成的列 回到应用程序。 除了身份之外,这可能是例如时间戳列。 但身份是最有用的。

    我们需要做的就是设置插入命令来返回身份。 有几种方法可以做到,例如:

    a) 使用带有输出参数的存储过程。这是“真实”数据库中最便携的方式。

    b) 使用多个 SQL 语句,最后一个返回插入的行。这是特定于 SQL Server 的 AFAIK,但最简单:

    insert into Parent (Col1, Col2, ...) values (@Col1, @Col2, ...);
    select * from Parent where Id = SCOPE_IDENTITY();
    

设置完成后,您需要做的就是创建具有 Ids 的父行,这些父行是唯一的(在单个数据集中)但在数据库中是不可能的。负数通常是一个不错的选择。然后,当您将数据集更改保存到数据库时,所有新的父行都会从数据库中获得真正的Ids。


注意:如果您碰巧使用没有多语句支持且没有存储过程(例如 Access)的数据库,则需要在父表适配器中的 RowUpdated 事件上设置事件处理程序。在 hanler 中,您需要使用 select @@IDENTITY 命令获取身份。


一些链接:

MSDN: Retrieving Identity or Autonumber Values (ADO.NET) MSDN: Managing an @@IDENTITY Crisis Retrieving Identity or Autonumber Values into Datasets C# Learnings: Updating identity columns in a Dataset

【讨论】:

我知道这篇文章很旧,但它似乎解决了我的问题;除了我的数据集来自 XML 文件,然后我想插入到数据库中。我想知道使用负值是否会导致我的孩子恢复这些关系。【参考方案2】:

需要指出的几件事。

    是的,您肯定需要为两个表分配关系。您可以从 xsd 编辑器检查(双击您的 xsd 文件)。默认情况下,关系设置为“仅关系”,没有任何“更新规则”。通过进入“编辑关系”并选择“仅外键约束”或“两者~~~”来编辑此关系。并且需要将“更新规则”设置为级联! “删除规则”由您决定。

    现在,当您将新的父表行的 ID (AutoIncrement) 用于新的子表行作为外键时,您必须先将父行添加到表中,然后才能使用新的父行的 ID。

    一旦您使用 tableadapter 为父表调用 Update,关联的子表的新行将自动具有正确的 parentID。

我的简单代码sn-ps:

'--- Make Parent Row
Dim drOrder as TOrderRow = myDS.TOder.NewTOrderRow
drOrder.SomeValue = "SomeValue"
myDS.TOrder.AddTOrderRow(drOrder) '===> THIS SHOULD BE DONE BEFORE CHILD ROWS

'--- Now Add Child Rows!!! there are multiple ways to add a row into tables....
myDS.TOrderDetail.AddTOrderDetailRow(drOrder, "detailValue1")
myDS.TOrderDetail.AddTOrderDetailRow(drOrder, "detailvalue2")
'....
'....

'--- Update Parent table first
myTableAdapterTOrder.Update(myDS.TOrder)
'--- As soon as you run this Update above for parent, the new parent row's AutoID(-1)
'--- will become real number given by SQL server. And also new rows in child table will
'--- have the updated parentID

'--- Now update child table
myTableAdapterTOrderDetail.Update(myDS.TOrderDetail)

希望对你有帮助!

【讨论】:

【参考方案3】:

如果您不想使用数据集,但又不想将 id 分配给孩子并获取 id 以便您可以更新模型: https://danielwertheim.wordpress.com/2010/10/24/c-batch-identity-inserts/

【讨论】:

以上是关于如何使用自动生成的标识密钥更新数据集父子表?的主要内容,如果未能解决你的问题,请参考以下文章

如何使此公式自动更新工作表参考?

Hibernate 自动更新表出错 建表或添加列,提示标识符无效

SQL自动增长列数据变动刷新的问题

如何获取共享密钥以在应用程序购买中自动更新?

每次在 Google Cloud Storage 上上传 CSV 时如何触发自动更新 Google BigQuery 数据集

SQL数据库中如何从A表自动更新数据到B表?