c# - 如何防止自引用表变成循环

标签 c# sql sql-server circular-reference

这是一个很常见的问题,但我还没有找到我正在寻找的确切问题和答案。

我有一个表有一个 FK 指向它自己的 PK,以启用任意深度的层次结构,比如经典的 tblEmployee 有一个列 Manager 这是一个 FK 与 PK tblEmployee.EmployeeID .

假设在我的应用中,用户

  1. 任命新员工 Alice 和 Dave,没有经理,因为他们是 CEO 和总裁。所以 tblEmployee.Manager 对于这两条记录是 NULL。
  2. 创建新员工鲍勃,爱丽丝担任经理。然后创建 Charles,Bob 作为他的经理。他们的经理字段包含 tblEmployee 中另一条记录的主键值。
  3. 为 Alice 编辑员工记录,这意味着指定 Dave 有她的经理(这很好)但不小心将 Alice 的经理设置为 Charles,他在树中比 Alice 低两级。

现在这个表是一个循环引用而不是一个正确的树。

确保第 3 步无法在应用程序中完成最佳方法是什么?我只需要确保它会拒绝执行最后的 SQL 更新,而是显示一些错误消息。

对于它是 SQL Server 中的数据库约束(必须在 2008 年或 2012 年工作)还是我的 C# 应用程序的业务逻辑层中的某种验证例程,我并不挑剔。

最佳答案

您可以使用 CHECK CONSTRAINT 来验证管理器 ID 不是循环。你不能在检查约束中有复杂的查询,但如果你先把它包装在一个函数中,你可以:

create function CheckManagerCycle( @managerID int )
returns int
as
begin

    declare @cycleExists bit
    set @cycleExists = 0

    ;with cte as (
        select E.* from tblEmployee E where ID = @managerID
        union all
        select E.* from tblEmployee E join cte on cte.ManagerID = E.ID and E.ID <> @managerID
    )
    select @cycleExists = count(*) from cte E where E.ManagerID = @managerID

    return @cycleExists;

end

然后你可以使用这样的约束:

alter table tblEmployee
ADD CONSTRAINT chkManagerRecursive CHECK ( dbo.CheckManagerCycle(ManagerID) = 0 )

这将阻止添加或更新记录以从任何来源创建循环。


编辑:重要说明:检查约束在它们引用的列上进行验证。我最初对此进行编码是为了检查员工 ID 的周期,而不是经理 ID。但是,这不起作用,因为它仅在 ID 列发生更改时触发。这个版本确实有效,因为它会在 ManagerID 更改时触发。

关于c# - 如何防止自引用表变成循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23019384/

相关文章:

python - 齐柏林飞艇 : how to read a DataFrame with sql

java - MySQL 获取数据的问题

c# - 异步等待会丢失 http 上下文吗?

c# - 许可证执行系统在调用 wkhtmltopdf.exe 时被篡改 - win server 2008

sql - 如何为 n :m relations 设计历史记录

c# - SQL 查询表示未提供参数,但已添加到 SqlCommand 对象

sql - 一对多关系的约束

sql - 计算组百分比到小数点后 2 位 - SQL

c# - 单核cpu上的C#并行和多线程

c# - 使用带有动态匿名对象的 NHibernate 在 GroupBy 查询中进行选择