数据库设计:具有不同属性的对象

时间:2010-04-26 14:23:55

标签: mysql database-design innodb

我正在设计一个产品数据库,其中产品可以根据其类型具有非常不同的属性,但是每种类型的属性都是固定的,并且类型根本无法管理。 E.g:

杂志: title,issue_number,pages,copies,close_date,release_date
web_site:名称,带宽,匹配,date_from,date_to

我想使用InnoDB并在引擎允许的情况下强制执行数据库完整性。推荐的方法是什么?

我讨厌那些表有100列且大多数值为NULL的设计,所以我想到了这样的事情:

product_type
============

product_type_id INT
product_type_name VARCHAR

product
=======

product_id INT
product_name VARCHAR
product_type_id INT -> Foreign key to product_type.product_type_id
valid_since DATETIME
valid_to DATETIME

magazine
========

magazine_id INT
title VARCHAR
product_id INT -> Foreign key to product.product_id
issue_number INT
pages INT
copies INT
close_date DATETIME
release_date DATETIME

web_site
========

web_site_id INT
name VARCHAR
product_id INT -> Foreign key to product.product_id
bandwidth INT
hits INT
date_from DATETIME
date_to DATETIME

这可以处理级联产品删除但是......好吧,我不完全相信......

3 个答案:

答案 0 :(得分:5)

这是关系表阻抗不匹配的经典OO设计。您描述的表设计称为“每个子类的表”。与您的应用中的对象实际外观相比,三种最常见的设计都是妥协:

  1. 每个具体类的表
  2. 每个层次结构的表
  3. 每个子类的表
  4. 您不喜欢的设计 - “表有100列,大多数值为NULL” - 是一个表来存储整个特化层次结构。由于各种原因,这是最不灵活的,包括 - 如果您的应用需要新的子类,则需要添加列。您描述的设计可以更好地适应变化,因为您可以通过添加由product_type中的值描述的新子类表来添加扩展。

    剩下的选项 - 1.每个具体类的表 - 通常是不合需要的,因为在每个专业化表中实现所有公共字段时涉及重复。虽然,优点是您不需要执行任何连接,并且子类表甚至可以在非常大的系统中的不同数据库实例上。

    您描述的设计非常可行。以下变体是您使用ORM工具执行CRUD操作时的外观。请注意每个子类表中的ID如何是层次结构中父表的FK值。一个好的ORM将根据product.id和product.product_type_id中的鉴别器值的值自动管理正确的子类表CRUD。无论您是否计划使用ORM,请查看hibernate的联接子类文档,只是为了查看他们所做的设计决策。

    product
    =======
    
    id INT
    product_name VARCHAR
    product_type_id INT -> Foreign key to product_type.product_type_id
    valid_since DATETIME
    valid_to DATETIME
    
    magazine
    ========
    
    id INT -> Foreign key to product.product_id
    title VARCHAR
    ..
    
    web_site
    ========
    
    id INT -> Foreign key to product.product_id INT
    name VARCHAR
    ..
    

答案 1 :(得分:2)

您似乎大致走上正轨,除了您可能需要考虑“产品”与通常称为“库存单位”(SKU)之间的区别。 25个单位的纸夹(某种特定种类)与50个单位的纸盒相同吗?在商店或任何类型的库存系统方面,区别很重要;实际上,在某些情况下,包装中的一个简单区别是,相同的基础“产品”的数量相同,可能会为您提供不同的SKU来跟踪。

您需要决定要跟踪此问题的位置,如果它对您的应用程序很重要(可以按照您的要求布置产品,并在其他表格中处理SKU用途的包装,例如,即使某些应用程序可能只是轻微的开销)。

答案 2 :(得分:1)

这实际上是在经典RDBMS中“强制执行”某种OO设计的标准方法。

所有“常用”属性都在主表上(例如,如果它在产品表级别保留,则可以很容易地成为主表的一部分),而具体数据则在子表上。

理论上,如果您有子类型(例如,杂志可以在日报和4色期刊中分类,也许,期刊有保质期的日期间隔),您也可以添加一个或多个子级别。 ..

这是非常常见(并经过验证)的设计。唯一的问题是主表总是至少与大多数操作的子表连接。如果你有数以万计的商品,这可能会影响性能。

另一方面,对于每种类型的子类型,一般操作如删除项目(我建议逻辑删除,在主表上将标志设置为“true”)。

无论如何,去吧。也许谷歌围绕“面向对象到RDBMS映射”或a complete discussion的某些东西。