填写表格的输入是一个大文件,它有唯一的animalIds,它们的名字,动物类型和其他一些动物类型的特定值。
数据库如下所示:
table animal:
- animalId(pk)
- name
- type(fk to animalType table)
table dogs:
- dogId(pk)
- animalId(fk to animal)
- hasCoat
- etc...
table fish:
- fishId(pk)
- animalId(fk to animal)
- animalId(fk to animal)
- dorsalFinCount
- etc...
我是这样设计的,因为我的另一个来源给了我一个独特的键(animalId,它识别世界各地的单一动物......就像一个uri)而且我不想拥有一个空值的大型单一数据库(例如,对于hasCoat和hasDorsalFin)也不必连续搜索两个类型特定的数据库。 此外,我可以轻松地扩展这个结构(表鸟,具有属性hasWing,wingColor等...)
我的(Java)程序设计如下所示:
abstract class Animal
- animalId
- name
- type
class Dog extends DatabaseObject
class Fish extends DatabaseObject
abstract class DatabaseObject
private UUID id;
public DatabaseObject(){this.uuid = UUID.randomUUID();}
public UUID getId();
问题是,Dog和Fish类是Animal,但需要为每个数据库条目设置一个UUID,因为在动物表中使用唯一的animalId作为PK。
此外,Dog和Fish也应该扩展Animal,因为它们需要那些数据字段......但这在Java中是不可能的,因为它们都已经扩展了抽象的DatabaseObject类。
一个解决方案可能是,Dog和Fish将Animal字段作为类成员,但这似乎是一个糟糕的方法。
您如何解决此问题以及您的设计(数据库和程序结构)的优点是什么?
修改 由于我的假设(...... PK不能用作另一张表中的PK)是错误的,我可以将dogId和fishId改为animalId。此外,这种数据库设计称为subtyping
答案 0 :(得分:2)
不要重新发明轮子,使用ORM。如果您可以使用Hibernate,那么已经有Inheritance Mapping功能。
答案 1 :(得分:1)
您的设计类似于称为类表继承的设计模式。你可以在这里访问同名的标签,或者你可以通过在网上搜索看到Martin Fowler对同一主题的处理。
我建议你做一个小改动。它可能适用于您的情况,也可能不适用。它被称为“共享主键”。你摆脱了DogId和FishId。相反,你将AminalID作为狗和鱼桌以及动物桌的PK。请注意,AnimalID将是PK和FK。当然,你必须让它成为动物PK的真实副本。
这有几个优点,其中包括简单性和速度。但最大的优点是它强制执行每个子类和超类之间的IS-A关系的一对一性质。