可以支持专用属性的数据库模式

时间:2010-11-29 13:31:04

标签: database-design properties relational-database

我需要存储一组实体,其中有几个专用版本。它们具有一些共同属性,但专用属性包含特定于该实体的属性。

解决方案

数据存储是一个关系型DBMS,这不是讨论:-)具体来说,它是Microsoft SQL Server 2005。

我可以轻松地为公共属性创建一个表,然后为每个专用版本创建一个表。但是,以后可能需要将新实体添加到解决方案中,并且我不希望同时维护对象模型数据库模式。

另一个想法是创建一个表

reading(<common properties>, extended_properties)

并让extended_properties字段成为扩展属性的某种序列化。我在想JSON或XML。我很可能会使用ORM框架,但我还没有决定。无论哪种方式,来自reading的专用实体的对象表示都可以公开包含{extended_property_name, value}字段中已解析的键/值对的字典extended_properties

从这个http://msdn.microsoft.com/en-us/library/ms345117(SQL.90).aspx我收集到XML字段,结合这些的模式,在DBMS中给出了类型化XML的概念。此外,涉及extended_properties字段中的XML内容的查询也可以考虑这些。

我想要什么

对我的解决方案建议的反馈,主要是带有reading表和扩展属性序列化的建议。

此外,我意识到这是关系DBMS与基于键/值的商店相比的局限之一。但是,肯定必须有一些建模技术来适应这种情况。

非常感谢任何反馈!

5 个答案:

答案 0 :(得分:13)

安德斯,不要放弃任何完整性或硬度,例如类型安全。

(回应即将来临)。

@Anders。不,完全没有,子类型很好(问题是你使用哪种形式,有什么不利/优势)。不要放弃任何力量或诚信或类型安全或检查或DRI。您选择的表单将需要额外的支票和一些代码(取决于您的平台)。

这个问题经常出现,但寻求者总是有一个狭隘的视角;我一直在不变的集合中制作相同的语句(子集)。我们的想法是评估所有选项。所以我正在写一篇文档。不幸的是,它需要更长时间也许4页。还没准备好发帖。但是图表已经完成,我认为你已经完成了,你可以马上使用它。

警告:仅有经验的项目施工工程师
道路不适合大篷车或具有高Eek因子的读者

链接到“正在构建的文档”中的▶Four Alternative Data Models◀。为地板上的烂摊子道歉;我很快就会收拾。

▶Link to IDEF1X Notation◀适用于不熟悉关系数据库建模标准的人。

  1. 它们都是关系型的,完整的。

  2. 6NF选项。今天的Relational(SQL)不支持6NF;它不会禁止它,它只是不提供5NF➔6NF结构。因此,您需要构建一个小目录,一些人称之为&#34;元数据&#34;。实际上,它只是标准SQL目录(sys表)的扩展。所需的控制级别在每个选项中建模。

  3. 基本上EAV完全正确,具有完全控制和完整性(类型安全,声明参照完整性等),而不是通常的混乱。

  4. 您可能对这些相关的问题/答案感兴趣(特别是,请查看数据模型):

    Multiple Fixed vs Abstract Flexible

    Database Schema-Related Problem

    "Simple" Database Design Problem

    对评论的回应

      

    ......这样,我们就可以轻松抓住&#​​34;评论&#34;与给定专用类型实例关联的行。这是这样做的方式,还是后来我会后悔这个决定?我们还缺少其他任何模式吗?

    不确定你的意思。注释,注释,地址,最终被许多表中使用(驻留在列中),所以正确的方法是规范化它们;提供一个评论表;从任何需要它的表中引用。这是一个通用的Comment表。它在Product(超类型)中使用,因为您声明了任何产品。它可以很容易地用在某些Product子类型中,而不是其他子类型中;在这种情况下,FK将处于所述产品子类型中。

    Your Data Model

      

    Product 5NF /子类型示例中ProductType表的用途是什么?它是否包含与每个专用产品相对应的行,例如ProductCPU?我认为它表明了基础产品的专业化。

    (图中的小错误,纠正了。)

    是的,确实。

    在标准关系术语中(不是作为数据库传递的不受控制的混乱),ProductType是 Discriminator ;它标识哪个产品子类型适用于此产品。告诉您需要加入哪个产品子类型表。这对组合在一起构成了一个合乎逻辑不要忘记生成视图,每个ProductType一个。

    • (对于四种数据模型中的每一种,请评估ProductType如何更改,确切地说它扮演的角色。)

    • &#34;泛化专业化&#34;是Oum术语的所有mumbo jumbo;没有越过界限,学习了Relational 30年来的能力。如果你对关系有一点了解,你将拥有全部的力量;否则你只能使用非常有限的面向对象的方法(Ambler和Fowler有很多答案)。请从 11月10日开始阅读this post。关系数据库模型实体,而不是对象;不是上课。

      

    例如,在添加新产品时,您希望提供一个下拉选项,其中包含可以添加的产品类型。根据这个选择,可以推断出将数据放入哪些表中。正确吗?我很抱歉谈论应用程序代码,但我只需要将其置于透视中

    是。接下来要提供哪个页面(带有字段),供用户输入数据。

    谈论将使用Rdb的应用程序代码没问题,他们像丈夫和妻子一样(不是丈夫和奴隶)。

    • 对于您的OO类,在完成Rdb建模后,将类树映射到Rdb,与任何将使用它的应用程序无关。不是相反。并且不依赖于一个应用程序。

    • 忘记&#34;坚持&#34;,它有很多问题(丢失的更新;损坏的数据完整性;有问题的调试;大规模争用;等等)。对Rdb的所有更新都应该在交易中,符合ACID标准,可以使用30年,但是Fowler和Ambler还没有读过它。通常这意味着一个存储的proc pre xact。

      

    判别式是我们之前建立的Type-table的FK。它表示基类型所遵循的 spec。子类型。但是判别表包含的内容是什么?

    数据模型不清楚吗? ProducType CHAR(1)(2). Name Char(30)

      

    可以是一个显示友好的文本,说明用户界面的类型,

    是的,除其他外,例如控制,约束等,在编码或报告时消除歧义。

      

    但是它是否还包含包含专用类型的确切表名?

    没有。这对于数据来说有点过于实际。原则上不允许。

    但没有必要。

      

    说我对ID = 1的产品感兴趣。它具有判别性,表明它是ProductCPU。您将如何从应用代码中检索此ProductCPU?

    如果您使用提供的模型并将其(所有表)实现为类,正确等等,这将很容易。您请求的示例将不使用视图(用于列表,更通用)。伪代码将是:

    • 给定ProductId(子类型未知,因此您不应该坐在特定于子类型的窗口中),仅加载Product超类型
    • 基于Discriminator Product.ProductType,设置指标等,并加载适用的子类型,ProductCPU; ProductMemory; ProductDisk; ProductTape之一;等

    • 我已经看到(并且不同意)同时加载给定ProductId的所有子类型的OO方法:一个子类型有效;其余的都是无效的。代码仍然必须根据Product将自身约束为Product.ProductType的有效类。

    或者,例如。在上下文所在的位置,用户坐在特定于子类型的窗口中,例如。 ProductCPU,设置该类,并请求ProductId xxx。然后使用ProductCPU视图。如果它返回零行,则它不存在。

    • 可能有ProductDisk xxx,但不是ProductCPU xxx。您是如何处理的,无论您是否指出产品`xxx但它不是CPU,都取决于应用程序的要求。

    对于列表,应用填充网格,而不考虑ProductId,使用视图(每个视图)加载每个网格。该SQL基于连接,不需要引用ProductType

答案 1 :(得分:1)

我会亲自为“为公共属性创建一个表,然后为每个专用版本创建一个表”方法。

原因:您说您的实施将在RDBMS中完成,这是不可协商的。精细。 倾倒非结构化,像blob一样的东西,比如DB字段中的序列化哈希表,这违背了RDBMS的设计理念,所以除非你把* extended_properties *字段视为不透明的想法,否则你会受到严重影响。 blob,就像一个gif或另一个二进制对象。

换句话说,忘记(有效地)查询“具有扩展属性的所有对象 COLOR = RED”。

您遇到的问题(在RDBMS中描述OO分类法)绝对不是新问题。有关选项的详细说明,请查看this

答案 2 :(得分:1)

这是gen-spec设计模式的典型例子。每个关于对象建模的教程都涵盖了Gen-spec,因为它是由继承处理的。在关系数据建模的教程中经常跳过它。但它很好理解。

对“泛化专业化关系建模”进行网络宣传。您将看到几篇关于如何为通用类设置单个表以及为每个专用类设置表的文章。这些文章将帮助您进行外键设计。特别是,每个专用表的主键都具有双重功能。它也是通用表的外键。

如果您习惯于对象建模,那么您将不会非常熟悉。但你会发现它运作良好。大多数文章提供的解决方案都不是动态的,因此每次发现新的专用子类时都必须执行一些DDL。

答案 3 :(得分:0)

以下是SO的五个例子。使用哪一个取决于您正在解决的实际问题以及您的偏好。

一般情况下,我建议不要将数据序列化到数据库字段中。

如果实体的专业版本相对较少,您只需使用类似以下示例的子类型: example one example two

对于较大的属性值,或者要动态定义属性(无架构更改),请查看观察模式的实现,如以下示例所示: example three example four ;或者进入所谓的第6种正常形式,如: example five 。请注意,“观察模式”是第6个NF的简化版本。

答案 4 :(得分:-1)

这种技术在设计和性能方面存在一些问题,但您似乎需要在灵活性方面做出妥协。

不必为每个属性创建特定的表甚至是新的字段,您可以为独特的属性创建一个表(并且它将非常大):

Unique_Property_ID
, FK_To_Some_Entity (Not sure what entity these link to: customers, bills, etc.) 
, Property_Type Not the data type but a link to a table describing this entity)
, Property_Value (Difficult to determine if all of your values will be of the same type: string, int, date, etc.)

示例:二手车经销商需要跟踪不同品牌和型号的附件(他们永远不知道他们会得到什么)。一些记录可能看起来像:

VehicleID   Property Type  Property Value
3           Sound System   Bose
3           Hybrid System  Battery
7           Starter Type   Hand Crank
7           Passenger Seat Rumble
9           Starter Type   Kick Start
9           Passenger Seat Side Car

每个Set |的每个值属性类型将有自己的记录。

另一个问题是当您希望将每个属性表示为一列时,您需要转置此表。