我有一个winforms应用程序,其中有两个DataGridViews显示来自Person和Address表的主 - 详细信息关系。 Person表具有PersonID字段,该字段是自动递增主键。地址有一个PersonID字段,即FK。
我用DataAdapter填充我的DataTables并设置Person.PersonID列的AutoIncrement = true和AutoIncrementStep = -1。我可以从DataGridView中插入Person DataTable中的记录。 PersonID列显示PersonID的唯一负值。我通过调用DataAdapter.Update(PersonTable)更新数据库,并且负数PersonID由SQL Server自动转换为正唯一值。
这就是问题。 Address DataGridView显示地址表,该表具有PersonID的PersonRelation。插入的人员记录具有临时负面PersonID。我现在可以通过DataGridView将记录插入Address,并将Address.PersonID设置为DataRelation映射的负值。我调用Adapter.Update(AddressTable),负的PersonID进入地址表,打破了关系。
你们如何使用DataTables和master-detail 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;
答案 0 :(得分:1)
您需要双击数据集设计器中的关系,然后选择Cascade Updates。当您的真实SQL服务器为您的Person表生成PK值时,它也会自动在地址表中设置外键值。
您不需要执行任何RowUpdated事件。它内置于数据集功能中。
答案 1 :(得分: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;
}
您想首先在父级上调用此方法。然后像往常一样做所有事情(更新父母,然后更新孩子)。
干杯!