VS2019+SQL Server12下WinForms主从DataGridView新增父记录异常
我之前碰到过一模一样的问题——用Visual Studio 2019和SQL Server 12在WinForms里做主从结构,父记录在窗体展示,子记录放DataGridView里。查看已有的记录完全正常,但**新增父记录(临时ID设为-1,数据库自动生成真实ID)**之后,子DataGridView居然还停留在上一个已保存的父记录上;新增子行的时候,还会关联到错误的父记录,根本不是刚新增的那个临时父记录。
先说说场景细节:涉及三张表,ResearchActivities作为父表,Contacts是关联表,ResearchActivitiesContacts用来实现多对多关系(这里把它当成父表的子表处理)。数据库本身是有外键约束的,但把表导入DataSet时,关系生成了但约束没显示出来,试了加不加约束都没解决问题。
当时我写的相关代码是这样的:
// 手动添加外键约束 relationship fkc = new global::System.Data.ForeignKeyConstraint( "FK__ResearchActvityContacts__ResearchActivity", new global::System.Data.DataColumn[] { this.tableResearchActivity.ResearchActivityIDColumn}, new global::System.Data.DataColumn[] { this.tableResearchActivityContacts.ResearchActivityIDColumn} ); this.tableResearchActivityContacts.Constraints.Add(fkc); fkc.AcceptRejectRule = global::System.Data.AcceptRejectRule.None; fkc.DeleteRule = global::System.Data.Rule.None; fkc.UpdateRule = global::System.Data.Rule.Cascade; // 子控件绑定源配置 this.researchActivityContactsBindingSource.DataMember = "FK__ResearchActvityContacts__ResearchActivity"; this.researchActivityContactsBindingSource.DataSource = this.researchActivityBindingSource; this.researchActivityBindingNavigator.BindingSource = this.researchActivityBindingSource; this.researchActivityContactsBindingNavigator1.BindingSource = this.researchActivityContactsBindingSource;
后来我找到了几个关键的解决步骤,亲测有效:
确保绑定源定位到新增的临时父记录
新增父记录后,researchActivityBindingSource可能并没有自动切换到刚新增的那一行(临时ID的行),导致子绑定源还是指向之前的父记录子集合。新增父记录后直接调用这句:researchActivityBindingSource.MoveLast();强制绑定源跳到最后一行——也就是刚新增的临时父记录,这样子绑定源会自动切换到对应的子集合。
检查父表的自增ID设置
要确保父表ResearchActivity的ResearchActivityID列在DataSet里的属性是:AutoIncrement = trueAutoIncrementSeed = -1AutoIncrementStep = -1
这样新增的临时行才会用负ID,和数据库生成的正ID区分开,DataSet才能正确识别临时记录和已持久化记录。
保存后同步真实ID到DataSet
当把新增的父记录保存到数据库后,数据库会生成真实的正ID,这时候必须把这个ID更新回DataSet的父记录里,同时因为你设置了UpdateRule = Cascade,DataSet会自动把子表ResearchActivitiesContacts里的临时外键ID替换成真实ID。
可以配置TableAdapter的插入命令,让它返回新生成的ID(比如用SCOPE_IDENTITY()),然后在更新后把这个ID赋值给父行的ResearchActivityID列,再调用AcceptChanges()。手动刷新子绑定源
如果上面的步骤做完还是有问题,在定位到新增父记录后,手动刷新子绑定源:researchActivityContactsBindingSource.ResetBindings(false);强制它重新从父绑定源获取当前行的子集合。
内容的提问来源于stack exchange,提问作者user994124

