基于EF/DataSet的WinForms主从DataGridView级联更新问题求助
WinForms 主从DataGridView级联更新最优实现方案
一、DataSet + TableAdapterManager 可靠实现方案
解决级联更新/删除失效问题
- 先确保SQL Server数据库中主从表的外键关联已勾选级联更新和级联删除
- 打开DataSet设计器,右键主从表的关系→属性,将更新规则和删除规则都设为
Cascade - 保存数据时直接调用TableAdapterManager的
UpdateAll方法,无需手动处理主从顺序:
Try Me.TableAdapterManager.UpdateAll(Me.YourDataSet) MessageBox.Show("保存成功") Catch ex As Exception MessageBox.Show("保存失败:" & ex.Message) End Try
ICollection 转 BindingList
如果是DataSet的DataTable数据,直接绑定:
DetailBindingSource.DataSource = New BindingList(Of YourDataSet.DetailRow)(YourDataSet.Detail)
如果是其他ICollection集合,转换方式:
Dim detailList As New List(Of Detail)(yourICollection) DetailBindingSource.DataSource = New BindingList(Of Detail)(detailList)
二、Entity Framework 最优实现方案
解决主从绑定无数据、切换主项残留问题
无需手动写CurrentChanged事件过滤,直接利用EF导航属性自动关联:
- 将主表BindingSource绑定到主DataGridView,数据源设为EF查询的主记录集合:
Using db As New YourDbContext() MasterBindingSource.DataSource = db.Masters.Include(Function(m) m.Details).ToList() End Using - 明细BindingSource的DataSource设为
MasterBindingSource,DataMember设为Master实体中明细导航属性的名称(比如Details)
这样切换主表行时,明细DataGridView会自动刷新对应数据,彻底解决旧数据残留问题
解决主键无法修改的报错问题
EF中实体主键是唯一标识,不允许直接修改,业务上需要变更主表ID的话,按以下步骤操作:
- 先删除原主记录及关联明细(数据库需开启级联删除)
- 新建主记录使用新ID
- 修改原明细的外键为新ID,重新关联到新主记录
增删改保存代码示例
Using db As New YourDbContext() Dim currentMaster = DirectCast(MasterBindingSource.Current, Master) ' 处理主记录 If currentMaster.Id = 0 Then db.Masters.Add(currentMaster) Else db.Entry(currentMaster).State = EntityState.Modified End If ' 处理新增/修改的明细 For Each detail In DirectCast(DetailBindingSource.List, BindingList(Of Detail)) If detail.Id = 0 Then db.Details.Add(detail) Else db.Entry(detail).State = EntityState.Modified End If Next ' 处理删除的明细 Dim deletedDetails = db.Details.Where(Function(d) d.MasterId = currentMaster.Id AndAlso Not DirectCast(DetailBindingSource.List, BindingList(Of Detail)).Contains(d)).ToList() db.Details.RemoveRange(deletedDetails) ' 提交保存 db.SaveChanges() MessageBox.Show("保存成功") End Using
让EF导航属性默认返回BindingList
在DbContext的OnModelCreating方法中配置,避免手动转换:
Protected Overrides Sub OnModelCreating(modelBuilder As DbModelBuilder) ' 配置主从关系及级联删除 modelBuilder.Entity(Of Master)().HasMany(Function(m) m.Details) .WithRequired(Function(d) d.Master) .HasForeignKey(Function(d) d.MasterId) .WillCascadeOnDelete(True) ' 设置导航属性为BindingList类型 modelBuilder.Entity(Of Master)().Collection(Function(m) m.Details).Type(Of BindingList(Of Detail))() End Sub
内容的提问来源于stack exchange,提问作者Roberto Hernandez
相关产品推荐
相关产品推荐

