防止循环和多个级联路径

时间:2014-08-27 21:01:51

标签: sql sql-server entity-framework

我有以下SQL表:

create table dbo.Companies (
  Id int identity not null constraint primary key clustered (Id),   
);

create table dbo.Workers (
  Id int identity not null constraint primary key clustered (Id),  
  CompanyId int not null,
);

create table dbo.Evaluations (
  Id int identity not null constraint primary key clustered (Id),       
  CompanyId int not null,
  WorkerId int not null 
)

以下约束:

alter table dbo.Workers
add constraint FK_Workers_CompanyId foreign key (CompanyId) references dbo.Companies(Id) on delete cascade on update cascade;

alter table dbo.Evaluations
add constraint FK_Evaluations_CompanyId foreign key (CompanyId) references dbo.Companies(Id) on delete cascade on update cascade,
    constraint FK_Evaluations_WorkerId foreign key (WorkerId) references dbo.Workers(Id) on delete no action on update no action;

我正在使用Entity Framework,当我尝试插入记录时,我收到错误:

Additional information: Introducing FOREIGN KEY constraint 'FK_dbo.Workers_dbo.Companies_CompanyId' on table 'Workers' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.

我应该更改约束还是应该更改数据库设计?

让我解释一下为什么我这样设计我的数据库:

1 - CompanyId in Workers表显示公司工作人员目前正在工作

2 - 评估中的CompanyId表明在进行评估时工人的工作地点......而且工人显然显示了被评估的工人。

对我而言,这一切都有道理,但也许我错了......

1 个答案:

答案 0 :(得分:1)

更明确:

CREATE TABLE dbo.EventTypes (
      EID INT PRIMARY KEY IDENTITY(1,1)
    , EventDescription VARCHAR(40)
);
INSERT INTO dbo.EventTypes (EventDescription) VALUES ('Hired');
INSERT INTO dbo.EventTypes (EventDescription) VALUES ('Evaluated');

这些将被使用和评估以确定发生了什么,时间在下面。

CREATE TABLE dbo.Companies (
      CID INT PRIMARY KEY IDENTITY(1,1)
    /* ... */
);
CREATE TABLE dbo.Workers (
      WID INT PRIMARY KEY IDENTITY(1,1)
    /* ... */
);

CREATE TABLE dbo.History (
      HistID INT PRIMARY KEY IDENTITY(1,1)
    , TS DATETIME NOT NULL DEFAULT GETDATE()
    , CompanyID INT NOT NULL FOREIGN KEY REFERENCES dbo.Companies(CID) ON UPDATE CASCADE ON DELETE CASCADE
    , WorkerID INT NOT NULL FOREIGN KEY REFERENCES dbo.Workers(WID) ON UPDATE CASCADE ON DELETE CASCADE
    , EventTypeID INT NOT NULL FOREIGN KEY REFERENCES dbo.EventTypes(EID) ON UPDATE CASCADE ON DELETE CASCADE
    /* ...other generic history-traits... */
);
CREATE NONCLUSTERED INDEX Idx_History_TS ON dbo.History (TS) INCLUDE (CompanyID, WorkerID, EventTypeID) WITH (FILLFACTOR = 90);
CREATE NONCLUSTERED INDEX Idx_History_CompanyID ON dbo.History (CompanyID) WITH (FILLFACTOR = 90);
CREATE NONCLUSTERED INDEX Idx_History_WorkerID ON dbo.History (WorkerID) WITH (FILLFACTOR = 90);
CREATE NONCLUSTERED INDEX Idx_History_EventTypeID ON dbo.History (EventTypeID) WITH (FILLFACTOR = 90);

这将包含一系列事件,您可以将事件子类化为令人愉悦的事件。例如,当关联的EventDescription ='Evaluated'时,您的代码可以在此处查看:

CREATE TABLE dbo.Evaluations (
      EvalID INT NOT NULL PRIMARY KEY FOREIGN KEY REFERENCES dbo.History(HistID) ON UPDATE CASCADE ON DELETE CASCADE
    /* ...Eval columns... */
);

CREATE TABLE dbo.EvaluationItems (
      ID INT PRIMARY KEY IDENTITY(1,1)
    , EvalID INT NOT NULL FOREIGN KEY REFERENCES dbo.Evaluations (EvalID)
    /* ...item details... */
);
GO

这只是作为模型提供的,评估项目不一定是这样。

接下来,最近的雇主:

CREATE VIEW dbo.WorkersLastEmployer AS
    SELECT W.*, C.*
    FROM dbo.Workers W
        INNER JOIN (
            SELECT H.HistID, H.TS, H.CompanyID, H.WorkerID, MAX(TS)OVER(PARTITION BY H.WorkerID) AS LastHired
            FROM dbo.History H
                INNER JOIN dbo.EventTypes E ON E.EID = H.EventTypeID
            WHERE E.EventDescription = 'Hired'
        ) Hi ON Hi.WorkerID = W.WID
            AND Hi.TS = Hi.LastHired
        INNER JOIN dbo.Companies C on C.CID = Hi.CompanyID
GO

由于CompanyID被迁移到History,而Evaluations现在是一个直接的子类,这个视图用于评估公司Y的worker X:

CREATE VIEW dbo.WorkerEvalutations AS
    SELECT E.*, W.*, C.*
    FROM dbo.Evaluations E
        INNER JOIN dbo.History H on E.EvalID = H.HistID
        INNER JOIN dbo.Workers W on W.WID = H.WorkerID
        INNER JOIN dbo.Companies C on C.CID = H.CompanyID
GO

此结构在没有警告的情况下运行,并为您提供更易于扩展的框架。