我有以下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表明在进行评估时工人的工作地点......而且工人显然显示了被评估的工人。
对我而言,这一切都有道理,但也许我错了......
答案 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
此结构在没有警告的情况下运行,并为您提供更易于扩展的框架。