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

Any other optimal way to update the parent table's columns when a child table is updated?

我有几个table结构如下:

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
);

我需要遵循一个新程序,如果信息或设置 table 有任何更新,我将需要在 LastUpdatedBy 和 LastUpdatedDate 列上对 Person table 进行相关更新。

我首先想到的是创建一个 SQL 触发器,当 Info 或 Setting table 发生时自动更新 Person table。但是快速浏览几篇文章,指出应该避免使用 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+ tables,每一个至少包含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 触发器吗?如果可以,请根据您的回答进行解释。欢迎任何替代解决方案,性能第一。

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

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 

还有其他方法,比如做一个存储过程更新一个事务中的所有table,或者更新前端数据访问层(如果你的前端有很多要更新,那说明它结构错误:一个地方应该负责写入这个 table。如果你的前端代码中到处都是更新语句,嗯..那是一个糟糕的设计)所以一个专门的 class 维护这些两个 tables 正确..

现在我想说触发器是解决问题的最简单方法。它们不太受欢迎,虽然不是因为性能,而是因为它们开始增加令人困惑的后果。想象你是一个 c # 数据库经验有限的开发人员,不知道触发器是什么,而你在抱怨 "every time I update just this one table, all these other 27 tables change by magic! What's going on? Am I going crazy or what?" - 触发器违反了 "keep all your data updating code in one place" 这样的规则,这就是为什么设计系统的人在特定部分有特定工作, 不喜欢他们