我四处看看,发现了许多类似的问题:
但是在向表中插入多行时,更新多行触发器仍然存在问题。
代码概述 我有一个保留表,其中分别有一个ReservationID和TourComponentID列。当我插入到预订表中时,我有以下触发器用刚插入匹配表中的TourComponentID的预订行中的ReservationID更新TourComponent表:
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更新为具有新的预订时(在预订表中插入一行),此触发器可以完美地工作。但是,如果我尝试更新多个游览组件(将多个行插入到预订表中以更新TourComponent表中的多个行),则只会更新第一个游览组件,即任何行。
其他答案和研究表明我
触发器不是每行执行一次,而是基于一组 因此,对于整个DML操作,该操作仅执行一次。那么你 需要使用join语句将其与其他任何更新日期一样对待。 因此,我希望我在INSERTED表上的联接处理了多行,还是我误解了这一点?
有趣的是,如果将TourComponentID,ReservationID和INSERTED行计数的触发变量记录到临时表foo中,我可以看到两条记录插入到我的临时表中,每条记录的行数均为1。
使用sql profiler捕获在运行时执行的实际sql,并针对数据库手动运行它,从而根据需要更新了两行。只有在使用Entity Framework更新数据库(即运行应用程序)时,我才发现只有一行被更新。
我尝试将值记录到触发器中的表FOO
INSERT INTO FOO (TourComponentID, ReservationID, Rowcounts )
SELECT i.TourComponentID, I.ReservationID, 1 --@ReservationId
FROM
INSERTED I
这将记录两行,每行的行数均为1,并带有正确的tourcomponentsID和ReservationID,但TourComponent表仍然仅更新了一行。
任何建议都值得赞赏。
旅游组件ID在Ajax帖子中作为字符串传递到MVC Action,在该MVC Action中,旅游组件模型被填充,然后每次传递一次以在代码中进行更新
public void UpdateTourComponents(IEnumerable<TourComponent> tourComponents)
{
foreach (var tourComponent in tourComponents)
{
UpdateTourComponent(tourComponent);
}
}
这是对UpdateTourComponent的调用
public int UpdateTourComponent(TourComponent tourComponent)
{
return TourComponentRepository.Update(tourComponent);
}
和对Update的最终调用
public virtual int Update(TObject TObject)
{
Dictionary<string, List<string>> newChildKeys;
return Update(TObject, null, out newChildKeys);
}
因此,一次只发生一次插入,因此每个TourComponent都会调用一次我的触发器。这就是为什么当我在插入中计算@@ Rowcount并登录到Foo时,我得到的值为1。当我手动运行插入时,我得到了正确的预期结果,所以我同意@Slava Murygin测试,认为问题可能与触发器本身。我以为如果我们一个接一个地触发请求,那么可能是速度问题,所以我在触发器和代码中放置了一个等待时间,但这并不能解决问题。
我已经使用sql profiler来捕获仅在第一个插入触发器起作用时运行的sql。
有趣的是,当随后在SQL Management Studio中运行完全相同的sql时,触发器将按预期方式工作,并且两个游览组件都使用预订ID进行了更新。
还值得一提的是,所有表的约束都已删除。
还有其他建议可能导致此问题的原因吗?
答案 0 :(得分:2)
您遇到的问题与特定触发器不同。尝试查看要更新的表名称“ [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
答案 1 :(得分:0)
因此潜在的问题在于实体框架。
this.Property(t => t.CurrentReservationId).HasColumnName("CurrentReservationId");
是SQL数据访问层的一个属性。这正在被缓存,并导致从db中读取的数据不是最新数据,因此,如果在Reservations表中有一个插入,则第二个插入将被缓存的值覆盖,在我的情况下为NULL。 / p>
将行更改为此可以解决问题,并使触发器按预期工作。
this.Property(t => t.CurrentReservationId).HasColumnName("CurrentReservationId").HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed);
查看有关HasDatabaseGeneratedOption的更多信息