如何更新同一数据集中主表关键字段为自增字段的两关系表到数据库?

JadyZhu 2002-12-28 05:18:59
在本地的DataSet中有两表Tb1和Tb2,为主从关系,主表的关键字段为自增字段。

问题是,在本地的主表tb1增加记录,同时从表Tb2增加新记录(外键为Tb1的主键)但是,如果其它用户在数据库中表Tb1增加记录,则在Tb1保存到数据库时主键ID会自动在Tb1已有的ID再加1,也就是此时的Tb1主键ID便不是在数据集中的ID值了。这样,从表Tb2保存便会出错了,因为其真正的外键ID已经变了!!!

请各位给点思路!不胜感谢!
...全文
112 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
JadyZhu 2003-01-07
  • 打赏
  • 举报
回复
dy_2000_abc(芝麻开门):你说的是对的,问题解决了!!!很开心,太感谢你一直帮忙!

到帖子:
http://expert.csdn.net/Expert/topic/1325/1325420.xml?temp=1.928347E-02,为表示我的真心感谢,我要给你分(这边已结贴)!虽然分不多,但是我的心意!!!一定、一定。。。。。

根本的原因在于我用sda.Update(changes)更新,现在才明白。这样的话,只映射更新了数据集changes表中的Id,而用到的ds中表的Id却没有更新!!!
JadyZhu 2003-01-06
  • 打赏
  • 举报
回复

dy_2000_abc(芝麻开门):十分感谢

研究中......
dy_2000_abc 2003-01-04
  • 打赏
  • 举报
回复
下面的代码和上面给出的差不多,我试验了一下,可以将从表的外键正确更新,不过存在一些显示的缺陷(没有深究),你试验一下,如果有问题再到这里讨论。
建立上面所示的两张表r1,r2,将代码copy过去后还要将sqlConnection1.ConnectionString 改为你机器上的数据库连接。
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Data.SqlClient;

namespace WindowsApplication7
{
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.DataGrid dataGrid1;
private System.Windows.Forms.Button button1;
private System.Data.SqlClient.SqlConnection sqlConnection1;
DataSet ds;
SqlDataAdapter sda;
private System.ComponentModel.Container components = null;
public Form1()
{
InitializeComponent();
}
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
private void InitializeComponent()
{
this.dataGrid1 = new System.Windows.Forms.DataGrid();
this.button1 = new System.Windows.Forms.Button();
this.sqlConnection1 = new System.Data.SqlClient.SqlConnection();
((System.ComponentModel.ISupportInitialize)(this.dataGrid1)).BeginInit();
this.SuspendLayout();
this.dataGrid1.DataMember = "";
this.dataGrid1.HeaderForeColor = System.Drawing.SystemColors.ControlText;
this.dataGrid1.Location = new System.Drawing.Point(16, 8);
this.dataGrid1.Name = "dataGrid1";
this.dataGrid1.Size = new System.Drawing.Size(376, 224);
this.dataGrid1.TabIndex = 0;
this.button1.Location = new System.Drawing.Point(160, 248);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(72, 32);
this.button1.TabIndex = 1;
this.button1.Text = "button1";
this.button1.Click += new System.EventHandler(this.button1_Click);
//改为你的数据库连接
this.sqlConnection1.ConnectionString = ;
this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
this.ClientSize = new System.Drawing.Size(408, 294);
this.Controls.AddRange(new System.Windows.Forms.Control[] {this.button1,this.dataGrid1});
this.Name = "Form1";
this.Text = "Form1";
this.Load += new System.EventHandler(this.Form1_Load);
((System.ComponentModel.ISupportInitialize)(this.dataGrid1)).EndInit();
this.ResumeLayout(false);
}
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
private void Form1_Load(object sender, System.EventArgs e)
{
ds=new DataSet();
sda=new SqlDataAdapter("select * from r1",this.sqlConnection1);
sda.FillSchema(ds,SchemaType.Mapped,"r1");
sda.Fill(ds,"r1");
sda=new SqlDataAdapter("select * from r2",this.sqlConnection1);
sda.FillSchema(ds,SchemaType.Mapped,"r2");
sda.Fill(ds,"r2");
ds.Relations.Add("abc",ds.Tables[0].Columns[0],ds.Tables[1].Columns[1]);
this.dataGrid1.SetDataBinding(ds,"r1");
}
private void button1_Click(object sender, System.EventArgs e)
{
SqlCommand insert_r1=new SqlCommand("Insert into r1 (name) values (@name);select id,name from r1 where (id=@@IDENTITY)",this.sqlConnection1);
insert_r1.Parameters.Add(new SqlParameter("@name",SqlDbType.Char,0,"name"));
sda.InsertCommand=insert_r1;
SqlCommand delete_r1=new SqlCommand("delete from r1 where id=@id",this.sqlConnection1);
delete_r1.Parameters.Add(new SqlParameter("@id",SqlDbType.Int,4,"id"));
sda.DeleteCommand=delete_r1;
SqlCommand update_r1=new SqlCommand("update r1 set name=@name where id=@id",this.sqlConnection1);
update_r1.Parameters.Add(new SqlParameter("@id",SqlDbType.Int,4,"id"));
update_r1.Parameters.Add(new SqlParameter("@name",SqlDbType.Char,0,"name"));
sda.UpdateCommand=update_r1;
sda.Update(ds,"r1");
SqlCommand insert_r2=new SqlCommand("Insert into r2 (parent_id,name) values (@parent_id,@name);select id,parent_id,name from r2 where (id=@@IDENTITY)",this.sqlConnection1);
insert_r2.Parameters.Add(new SqlParameter("@parent_id",SqlDbType.Int,0,"parent_id"));
insert_r2.Parameters.Add(new SqlParameter("@name",SqlDbType.Char,0,"name"));
sda.InsertCommand=insert_r2;
SqlCommand delete_r2=new SqlCommand("delete from r2 where id=@id",this.sqlConnection1);
delete_r2.Parameters.Add(new SqlParameter("@id",SqlDbType.Int,4,"id"));
sda.DeleteCommand=delete_r2;
SqlCommand update_r2=new SqlCommand("update r2 set parent_id=@parent_id where id=@id",this.sqlConnection1);
update_r2.Parameters.Add(new SqlParameter("@id",SqlDbType.Int,4,"id"));
update_r2.Parameters.Add(new SqlParameter("@parent_id",SqlDbType.Char,0,"parent_id"));
sda.UpdateCommand=update_r2;
sda.Update(ds,"r2");
}
}
}
JadyZhu 2003-01-04
  • 打赏
  • 举报
回复
不好意思,问题没搞清,可以再加分!

dy_2000_abc(芝麻开门):
谢谢你的关注!我有参考你说的例子,里面说,只要在本地DataSet中设定关联,则更新时从表的外键会自动更新,可是我试了不行啊?!
我处理的方式是:在本地数据集中有主从表,对应两个DataAdapter。先在DataSet添加两表数据(主从数据),保存时,我先保存主表数据,此时主表的ID已经变化,接着保存从表数据,可是从表的外键ID并未发生变化??

各位给点思路吧!
JadyZhu 2003-01-04
  • 打赏
  • 举报
回复
dy_2000_abc(芝麻开门):感谢你的一直关注!

我把我的问题详细描述下吧:

我的问题和南赫(参考贴主)基本类似。

我现在正在做公司的管理系统,也就是会牵涉到订单、订单明细的问题。
现在正在做订单管理。其中主要处理订单表order和订单明细表orderDetail的数据。

order表 orderDetail表

orderId (自增字段,主键)-----> orderId(外键)
orderDate ..........
orderNo ..........
orderNote
......

此两表本地对应两DataAdapter,分别为daO和daOD,但两表共一个DataSet为dsOrder,在数据集内有定义关联,如上。

在增加一份客户订单记录时,我是这样实现的:
在order表增加一条订单记录,此时默认情况下orderId为1(假如);
在orderDetail表中增加订单内容,多项,但对应的外键orderId都为1。
也就是说,此时,在本地数据集内的order和orderDetail两表是正确关联的。
只是,主从表的数据都还没有被保存到数据库(因为一订单在没有订单内容时,此时该订单是还不成立的,所以只能在订单表order对应的订单明细表orderDetail表中也有对应记录时,该订单才能被保存)。

我先保存订单order表,此时,假设数据库中订单表已经有三条记录,则此时订单保存后,订单的orderId为4。

接着我保存orderDetail表,但此时它的外键orderId还是为1,也就是不能保存了,因为它的外键并没有和订单的实际Id同时发生变化!

主要的问题是:如何在保存时,让主从表的主外键保存到数据库后保持一致?
也就是,在order表保存后,如何让其的真正的ID映射到
orderDetail中的外键上,然后再保存orderDetail??(那它
的外键此时便是OK的,和主表一一对应)

不胜感谢帮忙!


dy_2000_abc 2003-01-04
  • 打赏
  • 举报
回复
处理这个问题有很多微妙的地方,关键问题是将数据库的主键值映射回DataSet。这个问题我处理过好几次,能否将代码贴出来。
JadyZhu 2003-01-03
  • 打赏
  • 举报
回复
dy_2000_abc(芝麻开门):
不好意思还是不很清楚,虽已结贴,但可再加分。

问题是:
在本地DataSet编辑主从表后(暂未保存),才更新主从表,如何使从表ParentID和主表保持一致,主要是在增加时。比如在DataSet主表中增加一记录,从表中增加一记录,在更新后如何使从表的外键ID和主表保持一致?我试在本地DataSet用关联,可是也不行!也有参考过你说的另外的帖子,还是不大懂。
JadyZhu 2002-12-29
  • 打赏
  • 举报
回复
十分感谢,研究下先!
dy_2000_abc 2002-12-28
  • 打赏
  • 举报
回复
举个例子来说。先创建两张表:
r1 :id,name
r2 :id,parent_id,name
将它们设置为主从关系r1.id---r2.parent_id

你说的问题的关键在于更新子表时,子表的parent_id为原来r1对应的id。解决的办法是在DataSet中给r和r2建立主从关系,并且r1更新时,将数据库实际生成的id值映射回来,也就是说r1更新后,r1.id值等于数据库里的id。由于在DataSet设置了主从关系,r2.parent_id就会自动更正,这样再更新r2时,得到的parent_id就是正确的了。

代码示例:
ds=new DataSet();
sda=new SqlDataAdapter("select * from r1",sqlConnection1);
sda.FillSchema(ds,SchemaType.Mapped,"r1");
sda.Fill(ds,"r1");
sda=new SqlDataAdapter("select * from r2",sqlConnection1);
sda.FillSchema(ds,SchemaType.Mapped,"r2");
sda.Fill(ds,"r2");
ds.Relations.Add("abc",ds.Tables[0].Columns[0],ds.Tables[1].Columns[1]);
dataGrid1.SetDataBinding(ds,"r1");
...
private void updateDatabase()
{
SqlCommand insert_r1=new SqlCommand("Insert into r1 (name) values (@name);select id,name from r1 where (id=@@IDENTITY)",sqlConnection1);
insert_r1.Parameters.Add(new SqlParameter("@name",SqlDbType.Char,0,"name"));
sda.InsertCommand=insert_r1;
SqlCommand delete_r1=new SqlCommand("delete from r1 where id=@id",sqlConnection1);
delete_r1.Parameters.Add(new SqlParameter("@id",SqlDbType.Int,4,"id"));
sda.DeleteCommand=delete_r1;
SqlCommand update_r1=new SqlCommand("update r1 set name=@name where id=@id",sqlConnection1);
update_r1.Parameters.Add(new SqlParameter("@id",SqlDbType.Int,4,"id"));
update_r1.Parameters.Add(new SqlParameter("@name",SqlDbType.Char,0,"name"));
sda.UpdateCommand=update_r1;
sda.Update(ds,"r1");
SqlCommand insert_r2=new SqlCommand("Insert into r2 (parent_id,name) values (@parent_id,@name);select id,parent_id,name from r2 where (id=@@IDENTITY)",sqlConnection1);
insert_r2.Parameters.Add(new SqlParameter("@parent_id",SqlDbType.Int,0,"parent_id"));
insert_r2.Parameters.Add(new SqlParameter("@name",SqlDbType.Char,0,"name"));
sda.InsertCommand=insert_r2;
SqlCommand delete_r2=new SqlCommand("delete from r2 where id=@id",sqlConnection1);
delete_r2.Parameters.Add(new SqlParameter("@id",SqlDbType.Int,4,"id"));
sda.DeleteCommand=delete_r2;
SqlCommand update_r2=new SqlCommand("update r2 set parent_id=@parent_id where id=@id",sqlConnection1);
update_r2.Parameters.Add(new SqlParameter("@id",SqlDbType.Int,4,"id"));
update_r2.Parameters.Add(new SqlParameter("@parent_id",SqlDbType.Char,0,"parent_id"));
sda.UpdateCommand=update_r2;
sda.Update(ds,"r2");
}
当然,实际的处理不会这么单纯,要考虑的情况会很多。如果你使用sql server,如果你给r1加一个触发器,触发器的代码会生成一个identity,那么结果就会是!@^#$~,具体请参考这里http://expert.csdn.net/Expert/topic/1147/1147612.xml?temp=.3728754

111,115

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • AIGC Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧