SQL中的继承。怎么保证呢?

时间:2014-09-01 14:25:22

标签: sql sql-server tsql

我正在尝试使用SQL Server在C#对象中创建继承,我有:

create table dbo.Evaluations
(
  Id int not null constraint primary key clustered (Id),  
  Created datetime not null
);

create table dbo.Exams
(
  Id int not null,  
  Value int not null
  // Some other fields
);

create table dbo.Tests
(
  Id int not null,  
  Order int not null
  // Some other fields
);

alter table dbo.Exams
add constraint FK_Exams_Id foreign key (Id) references dbo.Evaluations(Id);

alter table dbo.Tests
add constraint FK_Tests_Id foreign key (Id) references dbo.Evaluations(Id);

哪个会转换为:

public class Evaluation {}

public class Exam : Evaluation {}

public class Test : Evaluation {}

我认为这是要走的路,但我遇到了问题:

  1. 如何强制Evaluation只有一个Test或一个Exam,而不是两者都有?

  2. 要查找我的评估类型,我可以检查考试或测试null。但是,我应该在EvaluationType表中使用Evaluations吗?

  3. 注意: 实际上,我有4个子类型,每个子类型有大约40到60个不同的列。 在评估表中,我有大约20个常用列,这些列也是我经常查询的列,所以我得到列表。

2 个答案:

答案 0 :(得分:2)

首先,不要将order等保留字用于列名。

您可以选择做什么。对于这个简单的例子,我建议在evaluation表中只有两个外键引用,以及一些约束和计算列。像这样:

create table dbo.Evaluations
(
  EvaluationId int not null constraint primary key clustered (Id),
  ExamId int references exams(ExamId),
  TestId int references tests(TestId),
  Created datetime not null,
  EvaluationType as (case when ExamId is not null then 'Exam' when TestId is not null then  'Test' end),
  check (not (ExamId is not null and TestId is not null))
);

如果您有很多子类型,这种方法就不太实用了。但是,对于您的情况,它提供以下内容:

  • 对子表的外键引用。
  • 指定类型的列。
  • 验证每次评估最多只设置一种类型。

存储额外的,未使用的id确实有一点点开销,但这是一个很小的开销。

编辑:

使用四个子类型,您可以进入具有单个引用的另一个方向并键入父表,然后使用条件列和索引来强制执行约束:

create table dbo.Evaluations
(
  EvaluationId int not null constraint primary key clustered (Id),
  EvaluationType varchar(255) not null,
  ChildId int not null,
  CreatedAt datetime not null,
  EvaluationType as (case when ExamId is not null then 'Exam' when TestId is not null then  'Test' end),
  ExamId as (case when EvaluationType = 'Exam' then ChildId end),
  TestId as (case when EvaluationType = 'Test' then ChildId end),
  Other1Id as (case when EvaluationType = 'Other1' then ChildId end),
  Other2Id as (case when EvaluationType = 'Other2' then ChildId end),
  Foreign Key (ExamId) int references exams(ExamId),
  Foreign Key (TestId) int references tests(TestId),
  Foreign Key (Other1Id) int references other1(Other1Id),
  Foreign Key (Other2Id) int references other2(Other2Id)
);

在某些方面,这是解决问题的更好方法。它最大限度地减少了存储,并且可以扩展到其他类型。请注意,它使用计算列作为外键引用,因此它仍然保持关系完整性。

答案 1 :(得分:0)

我最好的经验是在一个表中包含所有列。 关系模型与面向对象设计不太友好。 如果将每个类视为一个表,则可以在“base-table”(基类)中获得大量行的性能问题,或者如果具有继承级别,则可能会遇到大量连接。

如果您希望最小化工作量以获得正确的结构,请创建自己的工具,该工具可以为所选类创建/更改表的脚本。事实上这很简单。然后,您还可以生成数据访问层。结果你将获得自动化工作者,你可以专注于复杂的任务,并将“受过训练的猴子”的工作委托给计算机而非人类。