3

我有一个带有两个 DataGridViews 的 winforms 应用程序,显示我的 Person 和 Address 表中的主从关系。Person 表有一个 PersonID 字段,它是自动递增的主键。Address 有一个 PersonID 字段,即 FK。

我用 DataAdapter 填充我的 DataTables 并设置 Person.PersonID 列的 AutoIncrement=true 和 AutoIncrementStep=-1。我可以从 DataGridView 在 Person DataTable 中插入记录。PersonID 列显示 PersonID 的唯一负值。我通过调用 DataAdapter.Update(PersonTable) 更新数据库,SQL Server 自动将负的 PersonID 转换为正的唯一值。

这就是问题所在。Address DataGridView 通过 PersonID 显示与 Person 有 DataRelation 的地址表。插入的人员记录具有临时负的 PersonID。我现在可以通过 DataGridView 将记录插入到 Address 中,并且 Address.PersonID 设置为 DataRelation 映射中的负值。我调用 Adapter.Update(AddressTable) 并且否定的 PersonID 进入地址表,打破了这种关系。

你们如何使用 DataTables 和主从 DataGridViews 处理主键/外键?

谢谢!史蒂夫

编辑:

经过更多的谷歌搜索,我发现 SqlDataAdapter.RowUpdated 事件给了我我需要的东西。我创建了一个新命令来查询使用@@IDENTITY 插入的最后一个id。它工作得很好。DataRelation 为我更新了 Address.PersonID 字段,因此需要先更新 Person 表,然后更新 Address 表。所有新记录都正确插入,并带有正确的 ID!

            Adapter = new SqlDataAdapter(cmd);
            Adapter.RowUpdated += (s, e) => 
            {
                if (e.StatementType != StatementType.Insert) return;
                //set the id for the inserted record
                SqlCommand c = e.Command.Connection.CreateCommand();
                c.CommandText = "select @@IDENTITY id";
                e.Row[0] = Convert.ToInt32( c.ExecuteScalar() );
            };
            Adapter.Fill(this);
            SqlCommandBuilder sb = new SqlCommandBuilder(Adapter);
            sb.GetDeleteCommand();
            sb.GetUpdateCommand();
            sb.GetInsertCommand();
            this.Columns[0].AutoIncrement = true;
            this.Columns[0].AutoIncrementSeed = -1;
            this.Columns[0].AutoIncrementStep = -1;    
4

2 回答 2

1

我有一个类似的问题,但我的解决方案有点不同。

@Noel Kennedy:您的解决方案不适用于 SQL Server 2005 CE,因为它不支持多条语句,并且 TableAdapter 不会生成更新父表中的自动增量列所需的刷新代码。

注意:您仍然需要关系中的级联更新,以便更新子表。

我还在我的 TableAdapter 中添加了一个方法,该方法足够通用,可以复制/粘贴到所有父 TableAdapter 中。我唯一改变的是标识行类型和索引(如果需要)。我还向 TableAdapter 添加了一个名为 GetIdentity() 的查询。您可以通过使用 sql="SELECT @@IDENTITY;" 添加标量查询,将其添加到数据集设计器中的 TableAdapter

现在自定义函数是:

public int InsertAndRefresh(System.Data.DataTable dataTable)
{
    int updated = 0;

    System.Data.DataRow[] updatedRows = dataTable.Select("", "", System.Data.DataViewRowState.Added);

    bool closed = (this.Connection.State == System.Data.ConnectionState.Closed);
    if (closed) 
        this.Connection.Open();

    foreach (System.Data.DataRow row in updatedRows)
    {
        updated+=this.Adapter.Update(new global::System.Data.DataRow[] { row });
        decimal identity = (decimal)this.GetIdentity();
        row[0] = System.Decimal.ToInt64(identity);
        row.AcceptChanges();
    }
    if (closed)
        this.Connection.Close();

    return updated;
}

您想先在父级上调用它。然后像往常一样做所有事情(更新父母然后孩子)。

干杯!

于 2009-06-16T22:33:48.617 回答
1

您需要在数据集设计器中双击关系,然后选择级联更新。当你的真实 SQL server 生成的 Person 表的 PK 值生成时,它也会自动在地址表中设置外键值。

您不需要执行任何 RowUpdated 事件。它内置在数据集功能中。

于 2009-05-08T23:28:15.200 回答