更新子表时更新父表列的任何其他最佳方法?

时间:2017-08-23 03:25:33

标签: c# sql sql-server database-trigger

我有几个表格结构如下:

CREATE TABLE Person
(
    PersonID INT PRIMARY KEY,
    Name NVARCHAR(255),
    LastUpdatedBy INT,
    LastUpdatedDate DATETIME
);

CREATE TABLE Info
(
    InfoID INT PRIMARY KEY,
    PersonID INT,
    Info NVARCHAR(255),
    LastUpdatedBy INT,
    LastUpdatedDate DATETIME
);

CREATE TABLE Setting
(
    SettingID INT PRIMARY KEY,
    PersonID INT,
    Setting NVARCHAR(255),
    LastUpdatedBy INT,
    LastUpdatedDate DATETIME
);

我面临一个新的程序,如果Info或Setting表有任何更新,我需要对LastUpdatedBy和LastUpdatedDate列上的Person表进行相关更新。

首先想到的是创建一个SQL触发器,在Info或Setting表执行时自动更新Person表。但是请快速浏览几篇文章,说明应该避免使用SQL触发器,因为创建它时这是一个非常昂贵的过程,

虽然有些人建议更改应用程序代码。例如,

using (var db = new DbContext())
{
    var result = db.Info.SingleOrDefault(x => x.InfoID == infoID);
    if (result != null)
    {
        result.Info = "Some new value";
        result.LastUpdatedBy = userID;
        result.LastUpdatedDate = DateTime.UtcNow;
        db.SaveChanges();
    }
}

需要改变并变得像这样。

using (var db = new DbContext())
{
    var result = db.Info.SingleOrDefault(x => x.InfoID == infoID);
    if (result != null)
    {
        result.Info = "Some new value";
        result.LastUpdatedBy = userID;
        result.LastUpdatedDate = DateTime.UtcNow;

        var person = db.Person.SingleOrDefault(x => x.PersonID == result.PersonID);
        if (person != null)
        {
            person.LastUpdatedBy = result.LastUpdatedBy;
            person.LastUpdatedDate = result.LastUpdatedDate;
        }
        db.SaveChanges();
    }
}
实际上,应用程序代码很庞大,需要进行大量的代码修改。

假设有30多个表,每个表包含至少100k的记录。如果可以创建触发器,则如下所示:

CREATE TRIGGER TriggerName ON dbo.Info
    AFTER INSERT, UPDATE
AS
    BEGIN 
        SET NOCOUNT ON;
        UPDATE  dbo.Person
        SET     LastUpdatedBy = INSERTED.LastUpdatedBy ,
                LastUpdatedDate = INSERTED.LastUpdatedDate
        FROM    INSERTED
        WHERE   dbo.Person.PersonID = INSERTED.PersonID
    END 
GO 

在这种情况下,是否应该真正避免使用SQL触发器?如果可以的话,请根据你的答案解释。任何替代解决方案都是受欢迎的,性能优先。

1 个答案:

答案 0 :(得分:1)

此处触发器是最佳的(从性能角度来看);它就像在前端代码中对一堆行运行更新语句一样。我不明白为什么你认为会有性能损失。您的触发器代码看起来应该更像这样:

CREATE TRIGGER TriggerName ON dbo.Info
AFTER INSERT, UPDATE
AS
BEGIN 
    SET NOCOUNT ON;
    UPDATE  dbo.Person
    SET     LastUpdatedBy = INSERTED.LastUpdatedBy ,
            LastUpdatedDate = INSERTED.LastUpdatedDate
    FROM    dbo.Person 
            INNER JOIN 
            INSERTED
            ON dbo.Person.PersonID = INSERTED.PersonID
END 
GO 

还有其他方法,例如创建一个更新事务中所有表的存储过程,或者更新前端数据访问层(如果您的前端有很多需要更新,则意味着它的结构错误:一个地方应该我有责任写这个表。如果你的前端代码有更新语句,那就好了......这是一个糟糕的设计)所以一个专门的类正确维护这两个表..

现在我说触发器是解决问题的最简单方法..它们并不是很受欢迎,但不是因为性能,而是因为它们开始增加令人困惑的后果......想象你作为ac#developer由于有限的数据库经验,不知道触发器是什么,而且你在抱怨“每次我更新这一张桌子时,其他所有27张桌子都会因魔术而改变!发生了什么事?我会发疯还是什么?” - 触发中断规则,例如“将所有数据更新代码保存在一个地方”,这就是为什么设计特定部件具有特定工作的系统的人不喜欢它们