更新子 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" 这样的规则,这就是为什么设计系统的人在特定部分有特定工作, 不喜欢他们
我有几个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" 这样的规则,这就是为什么设计系统的人在特定部分有特定工作, 不喜欢他们