在两个多对多表之间连接

时间:2014-10-09 11:49:11

标签: java jpa database-design surrogate-key

我在为基于Java的Web应用程序定义适当的数据库设计时遇到了一些麻烦。我有3个表(Tag,DT和Property),我的场景如下。每个标签可以包含许多Dts,每个DT可以分配给不同的标签,每个DT都有许多属性,每个属性可以在许多DT中使用。将DT分配给Tag时,用户可以为其所有属性设置值。

我的问题是如何定义一个关系,以便每个Tag可以根据分配给它的DT获得其属性值。在我的设计中缺少什么表和关系。我必须根据此db创建相对实体。

Tag1==> DT1 ==> Initial values1, property values set 1 ; 
Tag2==> DT1 ==> Initial values1, property values set 2 ;

这是db图。并且感谢您的帮助。

enter image description here

以下是一些示例数据

enter image description here

2 个答案:

答案 0 :(得分:2)

正如我所看到的,您的设计的核心问题是使用代理键。 没有必要始终为表创建数字单列键。 即使你这样做,这并不能保证你没有重复。 事实上,这迫使系统在表上保留更多索引,这就是 一项额外的工作要做。

  1. 一些概念:

    • 我使用单数作为表名,'cos表中的每个元组代表 关系的一个对象;
    • 我使用小写字母表和列名(标识符)和 关键字的大字母。我不喜欢数据库中的CamelCase;
    • 我将<table_name>_id用于PK列。由于单数,这也是可能的 表名;
    • 我为我创建的所有约束和索引使用前缀+表名+详细信息。

    你不必遵循它们,但坚持一致的命名是非常好的 您的设计模式。

  2. 我会从property_type词典开始:

    CREATE TABLE property_type (
        property_type   varchar(20) NOT NULL,
        CONSTRAINT p_property_type PRIMARY KEY (property_type)
    );
    

    它是一个单列表,仅用于提供可能的域 属性类型的值。我使用varchar(20),文字列很漂亮 精细。这样做的好处是 - 您不必通过数字加入此表 获得property_type_id=123意味着什么的关键。

  3. 属性:

    CREATE TABLE property (
        property_id     integer     NOT NULL,
        property_name   varchar(50) NOT NULL,
        property_type   varchar(20) NOT NULL,
        CONSTRAINT p_property PRIMARY KEY (property_id),
        CONSTRAINT u_property_name UNIQUE (property_name),
        CONSTRAINT f_property_type FOREIGN KEY (property_type)
          REFERENCES property_type ON UPDATE CASCADE
    );
    

    我决定在这里使用数字PK,因为我想你可能想要重命名属性 在某一点。如果您更改property_type,则会更新级别。

    尽管这里已经存在PK,但在这里必须对名称进行UNIQUE约束, 否则你有可能在你有同样命名属性的情况下结束 具有不同的ID。

  4. DT表:

    CREATE TABLE dt (
        dt_id       integer     NOT NULL,
        dt_name     varchar(50) NOT NULL,
        CONSTRAINT p_dt PRIMARY KEY (dt_id),
        CONSTRAINT u_dt_name UNIQUE (dt_name)
    );
    

    同样,仅仅PK还不够,还要创建UNIQUE约束。 虽然我会完全摆脱dt_id并且只会保留 dt_name并且会使它成为PK。

  5. DT的属性:

    CREATE TABLE dt_property (
        dt_id           integer     NOT NULL,
        property_id     integer     NOT NULL,
        initial_value   varchar(50) NOT NULL,
        CONSTRAINT p_dt_property PRIMARY KEY (dt_id, property_id),
        CONSTRAINT f_dt_id FOREIGN KEY (dt_id) REFERENCES dt,
        CONSTRAINT f_property_id FOREIGN KEY (property_id) REFERENCES property
    );
    

    这是与您的设计的第一个重大区别 - 使用了复合键。

    是的,这意味着您必须随时执行2列 请参阅此表中的条目。但这不是什么大问题,真的 - 你 设计表一次,你也写了一次你的查询,但你的软件 如果正确完成并且易于维护,可能会使用相当长的一段时间。 最好花一点时间编写查询并轻松维护 从长远来看。

  6. 标签:

    CREATE TABLE tag (
        tag_id      integer     NOT NULL,
        tag_name    varchar(50) NOT NULL,
        CONSTRAINT p_tag PRIMARY KEY (tag_id),
        CONSTRAINT u_tag_name UNIQUE (tag_name)
    );
    

    这只是另一本字典。同样,对于dt表,我真的想要 避免使用tag_id列并仅保留tag_name,使其也成为PK。

  7. 新表tag_dt介绍了:

    CREATE TABLE tag_dt (
        tag_id      integer     NOT NULL,
        dt_id       integer     NOT NULL,
        CONSTRAINT p_tag_dt PRIMARY KEY (tag_id, dt_id),
        CONSTRAINT f_tag_id FOREIGN KEY (tag_id) REFERENCES tag,
        CONSTRAINT f_dt_id FOREIGN KEY (dt_id) REFERENCES dt
    );
    

    此表是创建dt + tag关系所必需的。没有它,你有数据 重复 - 您可以在架构上看到它,您有2行Tag_name='Tag1'

  8. 最后,标签属性:

    CREATE TABLE tag_property (
        tag_id      integer     NOT NULL,
        dt_id       integer     NOT NULL,
        property_id integer     NOT NULL,
        a_value     varchar(50) NOT NULL,
        CONSTRAINT p_tag_property PRIMARY KEY (tag_id, dt_id),
        CONSTRAINT u_tag_property UNIQUE (tag_id, property_id),
        CONSTRAINT f_tag_property_tag FOREIGN KEY (tag_id, dt_id) REFERENCES tag_dt,
        CONSTRAINT f_tag_property_property FOREIGN KEY (dt_id, property_id)
          REFERENCES dt_property
    );
    

    此表是完整的复合键,它符合您的所有要求。 主键是tag_id, dt_id,它也是tag_dt表的外键, 所以你希望能够介绍以前没有定义过的东西。 接下来,tag_id, property_id是唯一的,这意味着标签的属性不能重复。 最后,dt_id, property_id引用dt_property表,这意味着 只有dt允许的属性才会被注册。

  9. 最后的笔记

    所有主键和唯一键都是通过大多数DBMS中的索引实现的。还有一些DBMS 即使省略了键的第一列,也可以使用复合索引(多列索引)。 至少PostgreSQL可以做到这一点,这是我最常用的。

    请检查您的dttag表,我强烈建议您删除代理 这些中的密钥就像property_type完成一样。

    我没有创建任何额外的索引,通常我会在实现数据模型之后执行此练习,并对其进行一些真正的查询。

    另外,请勿对列名使用valuename。这些是保留字,您可能会在您选择的DBMS的未来版本中产生意想不到的影响。

答案 1 :(得分:1)

DB Design完全没问题。

只需使用Tag_DT和DT_Property表

以下是示例查询

select a.id_tag,b.id_Property
from 
tag_dt a,dt_property b
where a.id_dt = b.id_dt;