7

我有一个中等大小的 MySQL 数据库,其中包含一个主要的“人员”表,其中包含连接到剧院和戏剧学校的每个人的基本联系信息,我负责维护和开发许多 Web 应用程序。

有些人只是联系人——也就是说,他们的“persons”表记录是我们需要存储的关于他们的所有信息。许多其他人虽然必须能够为各种系统承担不同的角色。其中,大多数都是从学生开始的。有些人从员工开始。学生可以成为实习生或表演者;员工可以成为学生;所有教师都是雇员和表演者等。

从本质上讲,它们是任何个人可能必须佩戴的各种不同的“帽子”,以便访问系统的不同部分并与之交互,以及在我们网站的公共页面上提供有关它们的信息。

我对实现这个模型的选择是有几个其他的表来代表这些“帽子”——这些表包含补充基本“人”信息的元信息,所有这些都使用“人”ID作为他们的主键。例如,作为教师的人在教师表中有一条记录,其中包含他或她的简短传记信息和工资率。所有教师也是员工(但并非所有员工都是教师),这意味着他们在员工表中有一个记录,允许他们将工作时间提交到我们的工资系统中。

我的问题是,这样实现模型有什么缺点?我能想到的唯一另一个选择是用对于大多数条目来说是空的和无用的字段来填充persons表,然后有一个人可以属于的繁琐的“组”表,然后几乎每个表都有每个系统有一个 personperson_id外键,然后依赖业务逻辑来验证所引用的 person_id 是否属于适当的组;但这很愚蠢,不是吗?

下面是一些示例表声明,希望它们可以展示我当前如何将所有这些放在一起,并希望说明为什么我认为这是一种更明智的方式来模拟系统必须处理的各种情况的现实。

欢迎任何和所有的建议和意见。我很感激你的时间。

编辑一些受访者提到使用 ACL 来保证安全性——我在最初的问题中没有提到我实际上是在使用单独的 ACL 包来为不同系统的实际用户进行细粒度的访问控制。我的问题更多是关于在数据库模式中存储有关人员的元数据的最佳实践。

CREATE TABLE persons (
    `id`            int(11) NOT NULL auto_increment,
    `firstName`     varchar(50) NOT NULL,
    `middleName`    varchar(50) NOT NULL default '',
    `lastName`      varchar(75) NOT NULL,
    `email`         varchar(100) NOT NULL default '',
    `address`       varchar(255) NOT NULL default '',
    `address2`      varchar(255) NOT NULL default '',
    `city`          varchar(75) NOT NULL default '',
    `state`         varchar(75) NOT NULL default '',
    `zip`           varchar(10) NOT NULL default '',
    `country`       varchar(75) NOT NULL default '',
    `phone`         varchar(30) NOT NULL default '',
    `phone2`        varchar(30) NOT NULL default '',
    `notes`         text NOT NULL default '',
    `birthdate`     date NOT NULL default '0000-00-00',
    `created`       datetime NOT NULL default '0000-00-00 00:00',
    `updated`       timestamp NOT NULL,
    PRIMARY KEY (`id`),
    KEY `lastName` (`lastName`),
    KEY `email` (`email`)
) ENGINE=InnoDB;

CREATE TABLE teachers (
    `person_id`     int(11) NOT NULL,
    `bio`           text NOT NULL default '',
    `image`         varchar(150) NOT NULL default '',
    `payRate`       float(5,2) NOT NULL,
    `active`        boolean NOT NULL default 0,
    PRIMARY KEY (`person_id`),
    FOREIGN KEY(`person_id`) REFERENCES `persons` (`id`)
        ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB;

CREATE TABLE classes (
    `id`            int(11) NOT NULL auto_increment,
    `teacher_id`    int(11) default NULL,
    `classstatus_id` int(11) NOT NULL default 0,
    `description`   text NOT NULL default '',
    `capacity`      tinyint NOT NULL,
    PRIMARY KEY(`id`),
    FOREIGN KEY(`teacher_id`) REFERENCES `teachers` (`id`)
        ON DELETE RESTRICT ON UPDATE CASCADE,
    FOREIGN KEY(`classstatus_id`) REFERENCES `classstatuses` (`id`)
        ON DELETE RESTRICT ON UPDATE CASCADE,
    KEY (`teacher_id`,`level_id`),
    KEY (`teacher_id`,`classstatus_id`)
) ENGINE=InnoDB;

CREATE TABLE students (
    `person_id`     int(11) NOT NULL,
    `image`         varchar(150) NOT NULL default '',
    `note`          varchar(255) NOT NULL default '',
    PRIMARY KEY (`person_id`),
    FOREIGN KEY(`person_id`) REFERENCES `persons` (`id`)
    ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB;

CREATE TABLE enrollment (
    `id`                int(11) NOT NULL auto_increment,
    `class_id`          int(11) NOT NULL,
    `student_id`        int(11) NOT NULL,
    `enrollmenttype_id` int(11) NOT NULL,
    `created`           datetime NOT NULL default '0000-00-00 00:00',
    `modified`          timestamp NOT NULL,
    PRIMARY KEY(`id`),
    FOREIGN KEY(`class_id`) REFERENCES `classes` (`id`)
        ON DELETE RESTRICT ON UPDATE CASCADE,
    FOREIGN KEY(`student_id`) REFERENCES `students` (`id`)
        ON DELETE RESTRICT ON UPDATE CASCADE,
    FOREIGN KEY(`enrollmenttype_id`) REFERENCES `enrollmenttypes` (`id`)
        ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB;
4

9 回答 9

9

去年我也经历过类似的事情。问题是:我们是显式地还是一般地建模我们的实体?在您的示例中,这意味着拥有诸如教师、学生等实体/表,它们之间是否存在直接关系。

最后我们选择了一个通用的“Party”模型。党模型如下:

  • 一方代表个人或组织;
  • 大多数Party 类型都有一个依赖表来存储取决于Party 类型的额外信息,例如Person、Organization、Company;
  • 学生或老师之类的东西是派对角色。一个当事人可以有任意数量的当事人角色。例如,一个人可能既是教师又是学生;
  • 诸如类之类的东西作为Party Role Relations处理。例如,教师和学生角色之间的关系表示类关系;
  • 参与方角色关系可以具有额外信息的子类型。您的模型中的师生关系是一种注册,它可能具有您正在谈论的额外属性;
  • 各方之间没有直接关系。只有当事方角色相互关联;和
  • 对于常见的信息分组,如果有帮助,我们会创建视图,因为 SQL 可能有点复杂,因为关系更间接(例如,在教师和学生的党实体之间存在三个表)。

这是一个非常强大的模型,在 CRM 类型系统中非常常见。这个模型几乎来自“数据模型资源书:第 1 卷”,这是一个很好的资源。

于 2009-01-08T21:55:08.413 回答
1

您描述的组和帽子模型是可转换的,一个到另一个。无需担心数据丢失。具体来说,“master groups”表可以通过“hat person”表与各种“hat detail”表的外部连接来生成。

如果您使用的是“帽子”模型,则需要确保给定的“帽子表”准确地封装了该帽子的独特特征。与团体模型相比,那里的宽恕要少得多。

如果您采用这种方式,您可能需要为常见任务设置一些视图 - 例如,如果有人在“教师姓名”字段中输入,并且您想弹出一些自动完成功能,则视图基本上是

SELECT firstName, lastName 
FROM persons 
INNER JOIN teachers ON persons.id = teachers.person_id 

将有很大帮助。

顺便说一句,我发现有用的一件事是用与原始表中的主键相同的名称来调用外键。这样你就可以

INNER JOIN original_table USING (primary_key) 

在您的 FROM 中,而不是使用 WHERE 或 ON 等价物。

于 2009-01-08T21:37:34.627 回答
0

我以前用过Party模型。我真的解决了大部分的缺点。

于 2009-06-18T12:23:14.367 回答
0

我喜欢帽子方法。过去,我实现了帽子和组的组合。基本上,有一个用户可以执行的所有可能操作(权限)的列表。然后我有一个组表。每个组可以有 1 个或多个操作(权限)。然后我将用户分配到组。

这为我提供了很大的灵活性。我可以在我的许可中获得非常好的颗粒。我也可以通过编辑组来快速更改许多人的权限。事实上,我有权限页面设置来使用相同的权限。这允许最终用户(不是我)为其他用户设置权限。

于 2009-01-08T20:35:59.897 回答
0

是的,教师是唯一有这样的工资率的人。该字段应该更准确地称为“classPayRate”——这是教师雇员的特例。非教师员工在我们的工资系统中将他们的总小时数作为单独的行项目提交。

于 2009-01-08T20:37:44.030 回答
0

我可能会将教师更改为员工并添加员工类型。

但是,我绝不会在人员表中存储电子邮件、地址、电话。这些都应该是他们自己的单独表格,因为人们有多个电子邮件地址(工作和家庭)、多个电话号码(工作、家庭、手机、传真)和多个地址(工作、家庭 1、家庭 2、学校等)。我会将每个都放在自己的表中并为其分配一个类型,以便您可以识别哪个类型的地址、电话等。

同样对于地址、电子邮件、电话,您可能需要一个标志来识别哪个是首先用于联系的主要记录。我们调用我们的对应关系,它是一个通过触发器保持最新的布尔值,因为每个有记录的人必须有一个且只有一个对应关系,所以如果它发生变化,旧的必须自动重置以及新的进入,如果是第一个记录,它会自动设置,如果对应的记录被删除,如果有剩余记录,它将分配给另一个。

于 2009-01-08T20:38:05.650 回答
0

教师是唯一有工资的“人”吗?这样做可能会限制您的设计。您可能想要做的是有一个属性表来存储“人”的附加属性。这将允许将来进行修改。

于 2009-01-08T20:26:39.590 回答
0

为了安全起见,我更喜欢使用访问控制列表 (ACL)。使用 ACL,您可以拥有 Principal(用户或用户组)、Resources(例如文件、记录或记录组)和 Actions(例如读取、更新、删除)。

默认情况下,没有人有任何特权。要授予权限,您可以添加一个条目,例如 Bob 对 File Abc 具有读取权限。

您应该能够找到可以帮助您实现此类功能的代码。在 Java 中,JAAS 支持这种方法。

于 2009-01-08T21:06:00.353 回答
0

我正在使用 ACL 包来获得网站上的细粒度权限 - 我的问题的核心更多是关于如何为具有不同角色的个人存储元数据并在系统中构建一些保护措施以确保数据完整性(例如person 必须有一个教师记录才能被设置为班级的教师 - 外键约束引用教师表,而不是 person 表)。

于 2009-01-08T21:14:27.027 回答