Sql server SQL Server触发器连续快速插入行失败

Sql server SQL Server触发器连续快速插入行失败,sql-server,triggers,sql-update,database-trigger,Sql Server,Triggers,Sql Update,Database Trigger,我环顾四周,发现了许多类似的问题: 但在将多行插入表中时,我的触发器更新多行时仍然存在问题 守则大纲 我有一个Reservation表,它分别有ReservationID和TourComponentID列。当我插入到reservations表中时,我有以下触发器使用ReservationID更新TourComponent表,该行刚插入到reservation表中,并具有匹配的TourComponentID: CREATE TRIGGER [TR_Reservation_CurrentReserv

我环顾四周,发现了许多类似的问题:

但在将多行插入表中时,我的触发器更新多行时仍然存在问题

守则大纲 我有一个Reservation表,它分别有ReservationID和TourComponentID列。当我插入到reservations表中时,我有以下触发器使用ReservationID更新TourComponent表,该行刚插入到reservation表中,并具有匹配的TourComponentID:

CREATE TRIGGER [TR_Reservation_CurrentReservation] ON [Reservation] AFTER INSERT AS
UPDATE tc 
    SET tc.[CurrentReservationId] = I.ReservationID   
    FROM [tour].[TourComponent] tc 
    JOIN INSERTED I on I.TourComponentID = tc.TourComponentID
End
当更新一个tourComponent以拥有一个新的保留,并在保留表中插入一行时,此触发器可以完美地工作。但是,如果我尝试更新多个巡更组件,在预订表中插入多行以更新巡更组件表中的多行,则只更新第一个巡更组件,任何行

其他的答案和研究已经向我证明了这一点

触发器不是每行执行一次,而是作为基于集合的触发器执行 对于整个DML操作,只执行一次这样的操作。那么你呢 需要用join语句将其视为任何其他更新日期。 所以我希望我在插入表上的连接处理了多行,或者我误解了这一点

有趣的是,如果我将TourComponentID、ReservationID和INSERTED rowcount的触发器变量记录到一个临时表foo中,我可以看到两条记录被插入到我的临时表中,每个记录的rowcount为1

使用sql事件探查器捕获运行时执行的实际sql,并针对数据库手动运行此命令,我可以根据需要更新两行。只有在使用实体框架更新数据库(即运行应用程序)时,我才发现只有一行被更新

我已尝试将值记录到触发器中的表FOO中

INSERT INTO FOO (TourComponentID, ReservationID, Rowcounts )
    SELECT i.TourComponentID, I.ReservationID, 1  --@ReservationId 
    FROM
    INSERTED I
这将记录两行,每次的行数为1,并记录正确的tourcomponentsID和reservationID,但TourComponent表仍然只更新了一行

非常感谢您的建议

使现代化 在Ajax post中,巡更组件ID作为字符串传递给MVC操作,在MVC操作中填充巡更组件模型,然后在代码中一次更新一个

public void UpdateTourComponents(IEnumerable<TourComponent> tourComponents)
{
    foreach (var tourComponent in tourComponents)
    {
        UpdateTourComponent(tourComponent);
    }
}
最后一个更新的电话

public virtual int Update(TObject TObject)
{
    Dictionary<string, List<string>> newChildKeys;
    return Update(TObject, null, out newChildKeys);
}
所以每次插入一个,因此每个组件调用一次触发器。这就是为什么当我在INSERTED和log to Foo中计算@Rowcount时,得到的值为1。当我手动运行insert时,我得到了正确的预期结果,因此我同意@Slava Murygin测试的观点,即问题可能不在于触发器本身。我认为如果我们一个接一个地触发请求,可能会出现速度问题,所以我在触发器和代码中设置了等待,但这并没有解决它

更新2 我使用了一个sql分析器来捕获只有第一个insert触发器工作时运行的sql

有趣的是,当在SQLManagementStudio中运行完全相同的sql时,触发器会按预期工作,并且两个巡更组件都会使用预订id进行更新

还值得一提的是,所有表中的所有约束都已删除


还有什么其他建议可能导致此问题吗?

您遇到的问题与特定触发器不同。尝试查看正在更新的表名[tour].[TourComponent]或[dbo].[TourComponent]。 我已经试过你的扳机了,它非常有效:

use TestDB
GO
IF object_id('Reservation') is not null DROP TABLE Reservation;
GO
IF object_id('TourComponent') is not null DROP TABLE TourComponent;
GO
CREATE TABLE Reservation (
    ReservationID INT IDENTITY(1,1),
    TourComponentID INT
);
GO
CREATE TABLE TourComponent (
    CurrentReservationId INT,
    TourComponentID INT
);
GO
CREATE TRIGGER [TR_Reservation_CurrentReservation] ON [Reservation] AFTER INSERT AS
UPDATE tc 
    SET tc.[CurrentReservationId] = I.ReservationID   
    FROM [TourComponent] tc 
    JOIN INSERTED I on I.TourComponentID = tc.TourComponentID
GO
INSERT INTO TourComponent(TourComponentID)
VALUES (1),(2),(3),(4),(5),(6)
GO
INSERT INTO Reservation(TourComponentID)
VALUES (1),(2),(3),(4),(5),(6)
GO
SELECT * FROM Reservation
SELECT * FROM TourComponent

所以根本的问题是实体框架

this.Property(t => t.CurrentReservationId).HasColumnName("CurrentReservationId");
是SQL数据访问层的一个属性。这是被缓存的,导致从数据库中读取的数据不是最新的,因此,如果我们在保留表中有一个插入,那么第二个插入将被缓存的值覆盖,在我的情况下,这些值是空的

将行更改为该行可以解决问题,并使触发器按预期工作

this.Property(t => t.CurrentReservationId).HasColumnName("CurrentReservationId").HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed);

查看更多关于

的信息非常感谢您的测试,是的,我得到了类似的测试结果,所以我同意问题不在于触发器,而在于通过我的代码快速连续调用触发器。我已经添加了一个关于我的问题的更新,以显示代码的其他部分以及如何调用对预订表的插入。如果最近的预订是特定TourComponent感兴趣的预订,那么首先为什么要冗余存储该数据?您可能希望将这些信息一起显示在某个地方,但这并不意味着必须这样存储。@Damien_不相信这是存储每个预订的遗留代码,当前预订在按日期排序时是通过获取前1来读取的。我已将currentReservationId添加到tour组件表中,以提高此top 1查询的性能,因此需要为添加的任何新预订行提供触发器。读取旧的预订数据,以便在应用程序的其他区域对预订过程进行历史跟踪。如果您可以修改代码,请与我们联系 e存储过程进行插入,您将不需要触发器。
this.Property(t => t.CurrentReservationId).HasColumnName("CurrentReservationId").HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed);