Sql server 实体框架6在从绑定的DataGridView中删除时应使用DELETE时使用更新
我有一个Sql server 实体框架6在从绑定的DataGridView中删除时应使用DELETE时使用更新,sql-server,vb.net,winforms,datagridview,entity-framework-6,Sql Server,Vb.net,Winforms,Datagridview,Entity Framework 6,我有一个DataGridView绑定到BindingSource的DataMembertbl\u分销订单限制的DataSourcebs\u tbl\u系列制造商,它本身就是一个BindingSource,它有一个数据源链接到一个实体,ForeNET.tbl\u系列\u制造商。有问题的DataGridView仅显示与bs\u tbl\u Series\u制造商的当前记录相关的记录 tbl\u分销\u订单\u限制具有以下定义: CREATE TABLE [Fore].[tbl_Distributio
DataGridView
绑定到BindingSource
的DataMember
tbl\u分销订单限制的DataSource
bs\u tbl\u系列制造商
,它本身就是一个BindingSource
,它有一个数据源
链接到一个实体,ForeNET.tbl\u系列\u制造商
。有问题的DataGridView
仅显示与bs\u tbl\u Series\u制造商的当前记录相关的记录
tbl\u分销\u订单\u限制
具有以下定义:
CREATE TABLE [Fore].[tbl_Distribution_Orders_Restriction](
[GM_ORDER_NBR] [varchar](50) NOT NULL,
[Include] [bit] NOT NULL,
[AUS_SRS_CD] [varchar](2) NULL,
[ManufacturerID] [tinyint] NULL,
[CNTLG_DLR_CD] [varchar](6) NULL,
[FAWCode] [varchar](15) NULL,
CONSTRAINT [PK_tbl_Distribution_Orders_Restriction_1] PRIMARY KEY CLUSTERED
([GM_ORDER_NBR] ASC) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
ALTER TABLE [Fore].[tbl_Distribution_Orders_Restriction] WITH CHECK ADD CONSTRAINT [FK_tbl_Distribution_Orders_Restriction_tbl_Dealer] FOREIGN KEY([CNTLG_DLR_CD])
REFERENCES [Fore].[tbl_Dealer] ([cntlg_dlr_cde])
ALTER TABLE [Fore].[tbl_Distribution_Orders_Restriction] CHECK CONSTRAINT [FK_tbl_Distribution_Orders_Restriction_tbl_Dealer]
ALTER TABLE [Fore].[tbl_Distribution_Orders_Restriction] WITH CHECK ADD CONSTRAINT [FK_tbl_Distribution_Orders_Restriction_tbl_ModelCodes] FOREIGN KEY([FAWCode])
REFERENCES [Fore].[tbl_ModelCodes] ([FAWCode])
ALTER TABLE [Fore].[tbl_Distribution_Orders_Restriction] CHECK CONSTRAINT [FK_tbl_Distribution_Orders_Restriction_tbl_ModelCodes]
ALTER TABLE [Fore].[tbl_Distribution_Orders_Restriction] WITH CHECK ADD CONSTRAINT [FK_tbl_Distribution_Orders_Restriction_tbl_Series_Manufacturer] FOREIGN KEY([AUS_SRS_CD], [ManufacturerID])
REFERENCES [Fore].[tbl_Series_Manufacturer] ([aus_series_cde], [ManufacturerID])
ALTER TABLE [Fore].[tbl_Distribution_Orders_Restriction] CHECK CONSTRAINT [FK_tbl_Distribution_Orders_Restriction_tbl_Series_Manufacturer]
ALTER TABLE [Fore].[tbl_Distribution_Orders_Restriction] ADD CONSTRAINT [DF_tbl_Distribution_Orders_Restriction_Include] DEFAULT ((0)) FOR [Include]
CREATE TRIGGER [Fore].[trg_I_tbl_Distribution_Orders_Restriction]
ON [Fore].[tbl_Distribution_Orders_Restriction]
INSTEAD OF INSERT
AS
BEGIN
SET NOCOUNT ON
INSERT INTO Fore.tbl_Distribution_Orders_Restriction (GM_ORDER_NBR, [Include], AUS_SRS_CD, ManufacturerID, CNTLG_DLR_CD, FAWCode)
SELECT inserted.GM_ORDER_NBR, inserted.Include, Fore.qry_SOM_OrderInfo.AUS_SRS_CD, Fore.tbl_ModelCodes.ManufacturerID,
Fore.qry_SOM_OrderInfo.CNTLG_DLR_CD, Fore.qry_SOM_OrderInfo.FAWCode
FROM inserted INNER JOIN
Fore.qry_SOM_OrderInfo WITH (NOEXPAND) ON inserted.GM_ORDER_NBR = Fore.qry_SOM_OrderInfo.GM_ORDER_NBR INNER JOIN
Fore.tbl_ModelCodes ON Fore.qry_SOM_OrderInfo.FAWCode = Fore.tbl_ModelCodes.FAWCode
END
CREATE TRIGGER [Fore].[trg_U_tbl_Distribution_Orders_Restriction]
ON [Fore].[tbl_Distribution_Orders_Restriction]
INSTEAD OF UPDATE
AS
BEGIN
SET NOCOUNT ON
DELETE Fore.tbl_Distribution_Orders_Restriction
FROM deleted INNER JOIN Fore.tbl_Distribution_Orders_Restriction ON Fore.tbl_Distribution_Orders_Restriction.GM_ORDER_NBR=deleted.GM_ORDER_NBR AND Fore.tbl_Distribution_Orders_Restriction.[Include]=deleted.[Include]
INSERT INTO Fore.tbl_Distribution_Orders_Restriction (GM_ORDER_NBR, [Include], AUS_SRS_CD, ManufacturerID, CNTLG_DLR_CD, FAWCode)
SELECT inserted.GM_ORDER_NBR, inserted.Include, qry_SOM_OrderInfo.AUS_SRS_CD, Fore.tbl_ModelCodes.ManufacturerID, Fore.qry_SOM_OrderInfo.CNTLG_DLR_CD, Fore.qry_SOM_OrderInfo.FAWCode
FROM inserted INNER JOIN Fore.qry_SOM_OrderInfo WITH (NOEXPAND)
ON inserted.GM_ORDER_NBR = Fore.qry_SOM_OrderInfo.GM_ORDER_NBR INNER JOIN
Fore.tbl_ModelCodes ON Fore.qry_SOM_OrderInfo.FAWCode = Fore.tbl_ModelCodes.FAWCode
END
我的问题是:
当我从DataGridView
中删除一行时,该行将按预期消失。此时,我的事件代码调用Context.SaveChanges()
,但是,该行没有从数据库中删除,下次打开表单时,我认为已删除的所有记录仍然存在。任何时候都不会显示错误消息
我将Context.Database.Log
绑定到调试窗口,发现当我通过DataGridView
执行删除时,在执行Context.SaveChanges()
时会生成类似于以下日志输出的结果:
此SQL语句的最终结果是,[Fore].[tbl\u Distribution\u Orders\u Restriction]
中的“6W2CAA”记录没有任何更改,因为该表具有基于[GM\u ORDER\u NBR]
值填充字段的触发器,前一个字段的存在只是为了避免需要一个速度慢得令人无法接受的存储过程,该存储过程必须从许多其他表中查找这些值—在插入/更新时将查找负载转移到SQL Server更为可取
但是,即使这些触发器不存在,如果用户删除然后插入具有相同[GM\u ORDER\u NBR]
值的记录,也会发生错误,因为具有相同(主键)[GM\u ORDER\u NBR]
值的记录仍然存在,尽管为空[AUS\u SRS\u CD]
和[ManufacturerID]
值
我原以为实体框架在从DataGridView
删除后执行的SQL语句更像:delete from[Fore].[tbl\u Distribution\u Orders\u Restriction]其中([GM\u ORDER\u NBR]=@0)
当我.Remove
事件代码中的一个实体,然后是.SaveChanges
时,无效的更新仍然首先出现,然后是删除
如何让实体框架执行正确的DELETE
SQL语句,以响应DataGridView
删除,而不是(而不是补充)完全不合适的UPDATE
?实体框架不会对关系发出“DELETE”命令,DataGridView绑定到实体集合而不是实体集
当从EntityCollection中删除实体时,实体框架将只删除其由外键标识的关联或关系。实体框架不知道是否从数据库中删除它
考虑一个具有多个外键的实体
Table Products
PK ProductID
FK CategoryID (nullable)
FK VendorID (nullable)
假设产品与类别表和供应商表相关。现在,当您从一个类别中删除一个产品时,不必将其从表本身中删除。因为有些产品可能有类别,有些可能没有,类似地,有些可能定义了供应商,有些可能没有
这就是EF不删除实际记录的原因,它只是将其外键列设置为null。它从关联的表中删除一个实体,但该实体仍然存在
如果外键不可为null,则使用旧版本的EF抛出错误。我还不知道新的那个
理论上,如果外键为空,则子实体可以在没有其父实体的情况下存在,如果外键为非空,则子实体不能在没有其父实体的情况下存在,在这种情况下,应正确定义关系。我已经重写了SaveChanges方法,以识别不可为null的外键,并在记录的关联父项设置为null时相应地删除该记录
答复
您可以将DGV绑定到tbl_Distribution_Orders_Restriction的实体集,并为制造商DGV的SelectedItem设置条件/谓词。PrimaryKey
Akash Kava的回答很有启发性,它揭示了在我描述的情况下,记录是未链接的,而不是在“删除”时删除的。然而,他的“答案”是非常不充分的,因为,是的,您可以“将DGV绑定到tbl_分布_顺序_限制
的实体集,并为ForeginKey=制造商DGV的SelectedItem.PrimaryKey
”设置条件/谓词,然而,在这样做时,您将完全失去EF跟踪和对基础数据库数据进行更改的能力
然而,阿卡什·卡瓦的回答是一个有用的开始,所以我并没有简单地否决它
我找到的解决办法是:
加载tbl\u Distribution\u Orders\u Restriction
的数据,并将其过滤到绑定到BindingSource
的observateCollection
事件的CollectionChanged
处理程序,其中,ObservableCollection的更改被传播回源,并从源中传播回m_Context上的数据库。SaveChanges
:
UPDATE [Fore].[tbl_Distribution_Orders_Restriction]
SET [AUS_SRS_CD] = NULL, [ManufacturerID] = NULL
WHERE ([GM_ORDER_NBR] = @0)
-- @0: '6W2CAA' (Type = AnsiString, Size = 50)
-- Executing at 12/02/2014 8:15:51 AM +11:00
-- Completed in 142 ms with result: 1
Dim m_oc_tDSR = New ObjectModel.ObservableCollection(Of tbl_Distribution_Stock_Restriction)(From tDSR As tbl_Distribution_Stock_Restriction In m_Context.tbl_Distribution_Stock_Restriction.Local
Where tDSR.AUS_SRS_CD = m_CurrentSeries And tDSR.ManufacturerID = m_CurrentManufacturer
Select tDSR)
bs_tbl_Distribution_Stock_Restriction.DataSource = m_oc_tDSR
bs_tbl_Distribution_Stock_Restriction.ResetBindings(False)
AddHandler m_oc_tDSR.CollectionChanged, AddressOf m_oc_tDSR_CollectionChanged
m_oc_tDSR_集合的定义发生变化(实质上):
这允许仍在跟踪的已筛选实体集。您的数据源是否允许删除?数据源是否允许删除-我可以使用SQL在相关表或其他表上删除
Private Sub m_oc_tDOR_CollectionChanged(sender As Object, e As System.Collections.Specialized.NotifyCollectionChangedEventArgs)
Select Case e.Action
Case Specialized.NotifyCollectionChangedAction.Add
For Each tDOR As tbl_Distribution_Orders_Restriction In e.NewItems
m_Context.tbl_Distribution_Orders_Restriction.Add(tDOR)
Next
Case Specialized.NotifyCollectionChangedAction.Remove
For Each tDOR As tbl_Distribution_Orders_Restriction In e.OldItems
Try
m_Context.tbl_Distribution_Orders_Restriction.Remove(tDOR)
Catch ex As InvalidOperationException
End Try
Next
Case Specialized.NotifyCollectionChangedAction.Replace
For CtrA As Long = 0 To e.OldItems.Count - 1
m_Context.tbl_Distribution_Orders_Restriction.Remove(DirectCast(e.OldItems, tbl_Distribution_Orders_Restriction))
m_Context.tbl_Distribution_Orders_Restriction.Add(DirectCast(e.NewItems, tbl_Distribution_Orders_Restriction))
Next
End Select
End Sub