用于支持动态属性的模式

Joh*_*ren 17 database schema properties dynamic

我正在开发一个编辑器,使用户能够实时创建"对象"定义.定义可以包含零个或多个属性.属性的名称类型.创建定义后,用户可以创建该定义的对象并设置该对象的属性值.

因此,通过单击鼠标按钮,用户应该是.能够创建一个名为"Bicycle"的新定义,并添加"Numeric"类型的属性"Size".然后是另一个名为"Text"的属性,名为"Text",然后是另一个名为"Price"的属性,类型为"Numeric".完成后,用户应该能够创建一些"自行车"对象,并填写每辆自行车的"名称"和"价格"属性值.

现在,我已经在几个软件产品中看到过这个功能,所以它必须是一个众所周知的概念.当我坐下来试图想出一个DB模式来支持这个数据结构时,我的问题就开始了,因为我希望使用适当的列类型来存储属性值.IE浏览器.数字属性值存储为数据库中的INT,文本属性值存储为VARCHAR.

首先,我需要一个包含所有对象定义的表:

Table obj_defs

id | name      |
----------------
 1 | "Bicycle" |
 2 | "Book"    |
Run Code Online (Sandbox Code Playgroud)

然后我需要一个表来保存每个对象定义应具有的属性类型:

Table prop_defs

id | obj_def_id | name      | type |
------------------------------------
 1 |          1 | "Size"    |    ? |
 2 |          1 | "Name"    |    ? |
 3 |          1 | "Price"   |    ? |
 4 |          2 | "Title"   |    ? |
 5 |          2 | "Author"  |    ? |
 6 |          2 | "ISBN"    |    ? |
Run Code Online (Sandbox Code Playgroud)

我还需要一个包含每个对象的表:

Table objects

id | created    | updated    |
------------------------------
 1 | 2011-05-14 | 2011-06-15 |
 2 | 2011-05-14 | 2011-06-15 |
 3 | 2011-05-14 | 2011-06-15 |
Run Code Online (Sandbox Code Playgroud)

最后,我需要一个表来保存每个对象的实际属性值,并且该表的一个解决方案是为每个可能的值类型都有一个列,例如:

Table prop_vals

id | prop_def_id | object_id | numeric | textual | boolean |
------------------------------------------------------------
 1 |           1 |         1 |      27 |         |         |
 2 |           2 |         1 |         |  "Trek" |         |
 3 |           3 |         1 |    1249 |         |         |
 4 |           1 |         2 |      26 |         |         |
 5 |           2 |         2 |         |    "GT" |         |
 6 |           3 |         2 |     159 |         |         |
 7 |           4 |         3 |         |    "It" |         |
 8 |           5 |         3 |         |  "King" |         |
 9 |           6 |         4 |       9 |         |         |
Run Code Online (Sandbox Code Playgroud)

如果我实现了这个模式,prop_defs表的"type"列会保持什么?每个映射到列名称的整数,只是保存列名称的varchars?还有其他可能吗?存储过程会以某种方式帮助我吗?用于获取对象2的"name"属性的SQL是什么样的?

Ken*_*wns 28

您正在实现名为Entity-Attribute-Value模型的内容http://en.wikipedia.org/wiki/Entity-attribute-value_model.

很多人都会说这是一个坏主意(通常我就是其中之一),因为你最后一个问题的回答是"SQL取得什么......"往往是"厚厚的毛茸茸和令人讨厌,并且变得更糟".

一旦允许用户开始在其他对象中嵌套对象,这些批评就会持续存在,如果你不允许这样做,情况将保持可控.

对于你的第一个问题,"prop_defs表的"类型"列是什么",如果你有一个包含{"numeric","Any Number"},{"textual"的类型和描述的表,一切都会更简单,"String"}等.第一个值是主键.然后在prop_defs中,您的列"type"是该表的外键并保存值"numeric","textual"等.有些人会错误地告诉您总是使用整数键,因为它们加速更快,但如果您使用值"数字","文本"等你不必加入,最快的加入是你不做的.

获取单个值的查询将具有CASE语句:

SELECT case when pd.type = "numeric" then pv.numeric
            when pd.type = "textual" then pv.textual
            when pd.type = "boolean" then pv.boolean
  from prov_vals pv 
  JOIN prop_defs pd ON pv.prop_def_id = pv.id
 WHERE pv.object_id = 2
   AND pd.name = "Name"
Run Code Online (Sandbox Code Playgroud)

  • 那么,当需要嵌套物品出现时,EAV是否可以避免什么呢? (2认同)

Lor*_*dus 5

您必须接受关系数据库不擅长提供这种功能。他们可以提供,但不擅长。(我希望我是错的)。关系数据库更适合定义的接口,而不是改变接口。

--EAV 表提供动态字段,但性能不佳。糟糕的索引。而且查询起来很复杂。它可以在许多情况下完成工作,但在大量用户访问系统的大表上可能会崩溃。

-- 具有多个占位符列的“常规”表可以提高性能,但您会获得非描述性的列名,并且可以“添加”的列数受到限制。它也不支持子类型分离。

-- 通常,您在开发时创建/修改表,而不是运行时。我们真的应该歧视在运行时修改数据库吗?也许,也许不是。在运行时创建新表、外键和列可以实现真正的动态对象,同时提供“常规”表的性能优势。但是您必须查询数据库的架构,然后动态生成所有查询。那会很糟糕。它会完全打破表格作为界面的概念。