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