代码之家  ›  专栏  ›  技术社区  ›  Fuzzybear

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

  •  -1
  • Fuzzybear  · 技术社区  · 7 年前

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

    SQL Server A trigger to work on multiple row inserts

    SQL trigger multiple insert update

    Trigger to handle multiple row inserts and updates

    update multiple rows with trigger after insert (sql server)

    Trigger not working when inserting multiple records

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

    守则大纲

    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
    

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

    对于整个DML操作,只执行一次这样的操作。那么你呢 所以我希望我在插入表上的连接处理了多行,或者我误解了这一点?

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

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

    INSERT INTO FOO (TourComponentID, ReservationID, Rowcounts )
        SELECT i.TourComponentID, I.ReservationID, 1  --@ReservationId 
        FROM
        INSERTED I
    

    非常感谢您的建议。

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

    public void UpdateTourComponents(IEnumerable<TourComponent> tourComponents)
    {
        foreach (var tourComponent in tourComponents)
        {
            UpdateTourComponent(tourComponent);
        }
    }
    

    public int UpdateTourComponent(TourComponent tourComponent)
    {
        return TourComponentRepository.Update(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测试的观点,即问题可能不在于触发器本身。我认为如果我们一个接一个地触发请求,可能会出现速度问题,所以我在触发器和代码中设置了等待,但这并没有解决它。

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

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

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

    2 回复  |  直到 7 年前
        1
  •  2
  •   Slava Murygin    7 年前

    你有不同于那个特殊触发器的问题。请尝试查看正在更新的表名“[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
    
        2
  •  0
  •   Fuzzybear    7 年前

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

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

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

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

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

    HasDatabaseGeneratedOption