Dan*_*Dan 5 sql-server entity-framework
我正在尝试找出创建 SQL Server 主键、外键和约束的最佳方法,以在 LINQ/实体数据对象中准确表示我的数据模型。让我们假设 - 为简化起见 - 我有四个主要表 - Cats、Dogs、Pets 和 Owners - 以及一个关联表:OwnersToPets:
create table Cats (
ID_Cats int NOT NULL IDENTITY PRIMARY KEY,
Name nvarchar(50) NOT NULL,
miceEaten int NULL
)
create table Dogs (
ID_Dogs int NOT NULL IDENTITY PRIMARY KEY,
Name nvarchar(50) NOT NULL,
favouriteToy nvarchar(50) NULL
)
create table Owners (
ID_Owners int NOT NULL IDENTITY PRIMARY KEY,
Name nvarchar(50) NOT NULL,
)
create table Pets (
ID_Pets int NOT NULL IDENTITY PRIMARY KEY,
ID_Cats int references Cats(ID_Cats) NULL,
ID_Dogs int references Dogs(ID_Dogs) NULL
)
create table OwnersToPets (
ID_Owners int references Owners(ID_Owners) NOT NULL,
ID_Pets int references Pets(ID_Pets) NOT NULL
)
Run Code Online (Sandbox Code Playgroud)
当我通过从数据库导入来创建我的实体对象时,我得到以下信息:
问题是宠物和猫/狗之间的关系。每只猫/狗都有一个宠物参考。每个 Pet 对象都应该有一个 Cat 引用和一个 Dog 引用,其中之一将始终为 null。至少从概念上讲,猫/狗和宠物之间存在 1 比 0..1。
但是,实体数据模型在 Cats / Dogs 和 Pets 之间创建了 0..1 对多关系。
有什么建议?很显然,我的数据库已经存在,并且目前正在与我写的2版本,应用程序的版本1使用所以我宁愿不要有更改数据库太多。
您的问题中缺少很多信息
您当前模型的问题(如图所示)是 Pets 表:它目前没有增加任何值。当然,您的简化设计现在隐藏了可能有用的信息......
不过,我会提出一些带有假设的想法。
注意:这是正确的设计,EF 是否可以处理它。也就是说,您设计模型,实现数据库,然后让您的客户使用它
选项1:
假设一个所有者可以拥有 0..n 只狗和/或 0..n 只宠物,那么您需要 3 个对象表和 2 个链接表。你不需要宠物。
这允许每只狗和猫有多个主人。你当然可以在 Dog 和 Cat 中只拥有一个 OwnerID 来限制一个所有者。
您可以在此处为 Cat 和 Dog 设置不同的属性。
随着您添加更多类型,这变得笨拙(无论您如何建模所有者)
选项 2:
您是否需要将 Cat 或 Dog 区分为单独的实体?这不就是Pet的一个type属性吗?
**Pet
PetID, PK,
PetType, FK,
PetName
OwnerID, FK (optional, see below)
...
Run Code Online (Sandbox Code Playgroud)
您可以将链接表 PetOwner(多个所有者)或 OwnerID 作为 Pet(单个所有者)中的 FK。
这要求每个 Cat 或 Dog(或 Rabbit、Snake 等)对象具有相同的属性。
选项 3:
最后一种方法是超键/子类型。
这很有用,因为如果结合了选项 1(每只猫和狗的不同属性)和选项 2(保留宠物的想法)的元素
这定义了一个 Pet 对象,该对象恰好具有 Dog、Cat、Rabbit、Snake 等一种子类型。 super 键来自 Pet 中额外的 UQ1,用于强制执行子类型。作为表的宠物也存储了公共属性。
**Pet
PetID, PK, UQ1
PetType, UQ1, 'Dog' or 'Cat'
PetName
OwnerID, FK (optional, see below)
...
**Dog
PetID, PK, FK1
PetType, PK, FK1, constraint = 'Dog'
Breed -- per Dog,not per Pet
CatsChased
...
**Cat
PetID, PK, FK1
PetType, PK, FK1, constraint = 'Cat'
Breed -- per Cat, not per Pet
MiceEaten
...
Run Code Online (Sandbox Code Playgroud)
注意:UQ1 是 Cat 和 Dog 中 FK 使用的唯一约束。它是 Pet 上的“超级键”,允许通过 FK 设置子类型
同样,您可以将链接表 PetOwner(多个所有者)或 OwnerID 作为 Pet(单个所有者)中的 FK。
注意,PetType 可以是 Dog 和 Cat 中的常量派生列
编辑:添加了宠物、猫和狗的表格。
我认为所有者很明显......
CREATE TABLE PetSpecies (
PetSpeciesID tinyint NOT NULL IDENTITY (1,1),
Species varchar(100) NOT NULL,
CONSTRAINT PK_PetSpecies PRIMARY KEY CLUSTERED (PetSpeciesID),
CONSTRAINT UQ_PetSpecies UNIQUE (Species)
);
INSERT PetSpecies (Species) VALUES ('Dog');
INSERT PetSpecies (Species) VALUES ('Cat');
CREATE TABLE Pet (
PetID int NOT NULL IDENTITY (1,1),
PetSpeciesID tinyint NOT NULL,
PetName varchar(100) NOT NULL
OwnerID int NOT NULL,
...
CONSTRAINT PK_Pet PRIMARY KEY CLUSTERED (PetID),
CONSTRAINT FK_Pet_PetSpecies FOREIGN KEY (PetSpeciesID)
REFERENCES PetSpecies (PetSpeciesID),
CONSTRAINT FK_Pet_Owner FOREIGN KEY (OwnerID) REFERENCE Owner (OwnerID),
CONSTRAINT UQ_SuperKey UNIQUE (PetID, PetSpeciesID)
);
CREATE TABLE Dog (
PetID int NOT NULL,
PetSpeciesID tinyint NOT NULL,
CatsChased int NOT NULL,
CONSTRAINT PK_Dog PRIMARY KEY CLUSTERED (PetID, PetSpeciesID),
-- CONSTRAINT UQ_Dog UNIQUE (PetID),
CONSTRAINT CK_Cat CHECK (PetSpeciesID = 1 /*dog*/),
CONSTRAINT FK_Dog_Pet FOREIGN KEY (PetID, PetSpeciesID)
REFERENCES Pet(PetID, PetSpeciesID)
);
CREATE TABLE Cat (
PetID int NOT NULL,
PetSpeciesID tinyint NOT NULL,
MiceEaten int NOT NULL,
CONSTRAINT PK_Cat PRIMARY KEY CLUSTERED (PetID, PetSpeciesID),
-- CONSTRAINT UQ_Cat UNIQUE (PetID),
CONSTRAINT CK_Cat CHECK (PetSpeciesID = 2 /*cat*/),
CONSTRAINT FK_Cat_Pet FOREIGN KEY (PetID, PetSpeciesID)
REFERENCES Pet(PetID, PetSpeciesID)
);
Run Code Online (Sandbox Code Playgroud)
笔记:
猫和狗的PK可以是PetID
或PetID, PetSpeciesID
。后者更好地匹配外键。
对 cat 和 dog 的唯一约束是可选的,实际上,因为索引包含在 PK 中,并且 PetID 无论如何都是唯一的,如果 PetSpeciesID 被约束为单个值。
小智 0
首先,为什么要将 Pets 表限制为猫或狗。业主也可以两者兼得。而且EF定义的关系是绝对正确的。您想要的是与关系无关的数据操作限制。我不认为你能做到这一点
您面临的要求应该在模型级别解决。您可以使用验证来达到此目的。限制用户输入两者的值。
归档时间: |
|
查看次数: |
6763 次 |
最近记录: |