如何为在SQL中引用其他几个实体之一的实体建模?

时间:2013-02-14 19:25:45

标签: sql database-design sql-server-2008-r2 entity-relationship

我正在研究制造数据库的一部分。该业务接受自定义订单并根据规范构建项目。它们只构建几种(比方说3-10种)对象类型,但每种类型的对象在记录的规范中是不同的。我想要一个主制造表(mfgorders)列出一些常见字段,然后让它引用特定于所订购实体的规格表。我并不完全相信这是正确的做法。事实上,我根本没有信心。我所有的其他建模都是直截了当的,但是这个让我烦恼。

这是SQL:

CREATE TABLE dbo.mfgorders (MfgOrderId int NOT NULL
                                       IDENTITY (1, 1) ,
                        OrderId int NOT NULL,
                        LineNbr tinyint NOT NULL,
                        MfgTypeId tinyint NOT NULL,
                        ItemDescription varchar (999) ,
                        ManufacturingCost smallmoney,
                        CONSTRAINT PK_mfgorders PRIMARY KEY (MfgOrderId)) ;
--OrderId + LineNbr are a composite referencing a row on a lineitem table (not depicted here)

CREATE TABLE dbo.mfgorders_entity1 (MfgOrderId int NOT NULL,
                                EntitySize decimal (5, 3) ,
                                Width decimal (4, 2) ,
                                Thickness decimal (4, 2) ,
                                CONSTRAINT PK_mfgorders_entity1 PRIMARY KEY (MfgOrderId)) ;

CREATE TABLE dbo.mfgorders_entity2 (MfgOrderId int NOT NULL,
                                Height decimal (5, 2) ,
                                Width decimal (5, 2) ,
                                Thickness decimal (4, 2) ,
                                RotationSetting decimal (4, 1) ,
                                FinishedHeight decimal (5, 2) ,
                                FinishedWidth decimal (5, 2) ,
                                FinishedThickness decimal (4, 2) ,
                                CONSTRAINT PK_mfgorders_entity2 PRIMARY KEY (MfgOrderId)) ;

CREATE TABLE mfg_types (MfgTypeId tinyint NOT NULL,
                    ItemName varchar (32) NOT NULL,
                    ItemDescription nvarchar (64) NULL,
                    IsActive bit NOT NULL
                                 CONSTRAINT DF_mfg_types_IsActive DEFAULT 1,
                    SortOrder int NULL,
                    CONSTRAINT PK_mfg_types PRIMARY KEY (MfgTypeId)) ;

ALTER TABLE dbo.mfgorders_entity1 ADD CONSTRAINT FK_mfgorders_entity1_mfgorders FOREIGN KEY (MfgOrderId) REFERENCES dbo.mfgorders (MfgOrderId) ON UPDATE NO ACTION ON DELETE CASCADE;

ALTER TABLE dbo.mfgorders_entity2 ADD CONSTRAINT FK_mfgorders_entity2_mfgorders FOREIGN KEY (MfgOrderId) REFERENCES dbo.mfgorders (MfgOrderId) ON UPDATE NO ACTION ON DELETE CASCADE;

ALTER TABLE dbo.mfgorders ADD CONSTRAINT FK_mfgorders_mfg_types FOREIGN KEY (MfgTypeId) REFERENCES dbo.mfg_types (MfgTypeId) ON UPDATE NO ACTION ON DELETE CASCADE;

以下是上述代码的ER图:

ER-diagram

该模型意味着entity1和entity2可以拥有相同的MfgOrderId,当然我不希望这样。我希望MfgOrderId只引用其中一个实体。我想在我的脑海里,我希望利用mfg_types指向正确的实体表,但我觉得这个模型已经关闭,并且通过询问SO社区,我会为我的生活增加几年。

此致 约翰

3 个答案:

答案 0 :(得分:2)

“......我当然不希望这样。”

我不一定会跳到那个结论。您描述的模型是可接受的模型,Hibernate称之为InheritanceType.JOINED。您可以阅读它in their docs,但您可以使用共享相同ID的所有表对该关系进行建模。

JPA docs也谈论它。

关于使用它,或者实际上关于在数据库中表示类层次结构的关键部分是,您需要能够判断您是否具有entity1或entity2。最明确定义的方法是使用Discriminator,基本上是超类表中的一列,表示任何行是代表实体1还是实体2。

我相信如果你没有指定Discriminator,并且你正在使用JOINED,那么Hibernate(以及可能还有其他JPA实现)将通过检查所有子类表并查看哪一个包含一行来自动为你做一个特定的ID。假设每个MfgOrderId都在一个且只有一个子类表中,这对您有用而无需更改模式。

修改

我错误地切换了TABLE_PER_CLASS,我的意思是JOINED!

答案 1 :(得分:1)

您的设计表达或尝试的是超类型和子类型关系。

表达此信息的一种方法是在每个实体表中包含MfgTypeId字段:

CREATE TABLE dbo.mfgorders_entity2 (MfgOrderId int NOT NULL,
                 MfgTypeId tinyint NOT NULL,
                 Height decimal (5, 2) ,
                 Width decimal (5, 2) ,
                 Thickness decimal (4, 2) ,
                 RotationSetting decimal (4, 1) ,
                 FinishedHeight decimal (5, 2) ,
                 FinishedWidth decimal (5, 2) ,
                 FinishedThickness decimal (4, 2) ,
                 CONSTRAINT PK_mfgorders_entity2 PRIMARY KEY (MfgOrderId, MfgTypeId),
                 CONSTRAINT chkEntity2_MfgTypeID CHECK (MfgTypeId = 'Type Id for Entity 2')) ;

我可能还会更改MfgOrders表,以包含MfgTypeId作为主键的一部分。

CREATE TABLE dbo.mfgorders (MfgOrderId int NOT NULL IDENTITY (1, 1) ,
                 MfgTypeId tinyint NOT NULL,                 
                 OrderId int NOT NULL,
                 LineNbr tinyint NOT NULL,
                 ItemDescription varchar (999) ,
                 ManufacturingCost smallmoney,
                 CONSTRAINT PK_mfgorders PRIMARY KEY (MfgOrderId, MfgTypeId)) ;

如果您搜索Supertype&子类型数据库建模您将找到许多资源,包括SO和Stackexchange网络上的问题。我在下面添加了一些链接,可能会帮助您开始使用它:

  1. Supertype/Subtype on Database Administrators

  2. Supertypes & Subtypes

  3. how-to-implement-referential-integrity-in-subtypes

答案 2 :(得分:0)

我看不出你有什么重大问题。这是我可能会做的:

CREATE TABLE dbo.mfgorders (    MfgOrderId int NOT NULL IDENTITY (1, 1),
                            OrderId int NOT NULL,
                            LineNbr tinyint NOT NULL,
                            MfgTypeId tinyint NOT NULL,
                            ItemDescription varchar (999) ,
                            ManufacturingCost smallmoney,
                            CONSTRAINT PK_mfgorders PRIMARY KEY (MfgOrderId)) ;
--OrderId + LineNbr are a composite referencing a row on a lineitem table (not depicted here)

CREATE TABLE dbo.mfgorders_entity1( MfgOrderEntity1Id int NOT NULL IDENTITY (1, 1),
                                MfgOrderId int NOT NULL,
                                EntitySize decimal (5, 3) ,
                                Width decimal (4, 2) ,
                                Thickness decimal (4, 2) ,
                                CONSTRAINT PK_mfgorders_entity1 PRIMARY KEY (MfgOrderEntity1Id)) ;

CREATE TABLE dbo.mfgorders_entity2 (MfgOrderEntity2Id int NOT NULL IDENTITY (1, 1),
                                MfgOrderId int NOT NULL,
                                Height decimal (5, 2) ,
                                Width decimal (5, 2) ,
                                Thickness decimal (4, 2) ,
                                RotationSetting decimal (4, 1) ,
                                FinishedHeight decimal (5, 2) ,
                                FinishedWidth decimal (5, 2) ,
                                FinishedThickness decimal (4, 2) ,
                                CONSTRAINT PK_mfgorders_entity2 PRIMARY KEY (MfgOrderEntity2Id)) ;

CREATE TABLE mfg_types (            MfgTypeId tinyint NOT NULL,
                                ItemName varchar (32) NOT NULL,
                                ItemDescription nvarchar (64) NULL,
                                IsActive bit NOT NULL
                                CONSTRAINT DF_mfg_types_IsActive DEFAULT 1,
                                SortOrder int NULL,
                                CONSTRAINT PK_mfg_types PRIMARY KEY (MfgTypeId)) ;

ALTER TABLE dbo.mfgorders_entity1 ADD CONSTRAINT FK_mfgorders_entity1_mfgorders FOREIGN KEY (MfgOrderId) REFERENCES dbo.mfgorders (MfgOrderId) ON UPDATE NO ACTION ON DELETE CASCADE;

ALTER TABLE dbo.mfgorders_entity2 ADD CONSTRAINT FK_mfgorders_entity2_mfgorders FOREIGN KEY (MfgOrderId) REFERENCES dbo.mfgorders (MfgOrderId) ON UPDATE NO ACTION ON DELETE CASCADE;

ALTER TABLE dbo.mfgorders ADD CONSTRAINT FK_mfgorders_mfg_types FOREIGN KEY (MfgTypeId) REFERENCES dbo.mfg_types (MfgTypeId) ON UPDATE NO ACTION ON DELETE CASCADE;