devise数据库来保存不同的元数据信息
所以我试图devise一个数据库,这将允许我连接一个产品与多个类别。 这部分我已经想通了。 但是,我无法解决的是持有不同types的产品细节的问题。
例如,产品可能是一本书(在这种情况下,我会需要元数据,像isbn,作者等书)或它可能是一个商业目录(其中有不同的元数据)。
我应该如何解决这个问题?
这被称为观测模式。
替代文字http://www.damirsystems.com/dp_images/observation_model_3.png
三个对象,例如
Book Title = 'Gone with the Wind' Author = 'Margaret Mitchell' ISBN = '978-1416548898' Cat Name = 'Phoebe' Color = 'Gray' TailLength = 9 'inch' Beer Bottle Volume = 500 'ml' Color = 'Green'
这就是表格的样子:
Entity EntityID Name Description 1 'Book' 'To read' 2 'Cat' 'Fury cat' 3 'Beer Bottle' 'To ship beer in'
。
PropertyType PropertyTypeID Name IsTrait Description 1 'Height' 'NO' 'For anything that has height' 2 'Width' 'NO' 'For anything that has width' 3 'Volume' 'NO' 'For things that can have volume' 4 'Title' 'YES' 'Some stuff has title' 5 'Author' 'YES' 'Things can be authored' 6 'Color' 'YES' 'Color of things' 7 'ISBN' 'YES' 'Books would need this' 8 'TailLength' 'NO' 'For stuff that has long tails' 9 'Name' 'YES' 'Name of things'
。
Property PropertyID EntityID PropertyTypeID 1 1 4 -- book, title 2 1 5 -- book, author 3 1 7 -- book, isbn 4 2 9 -- cat, name 5 2 6 -- cat, color 6 2 8 -- cat, tail length 7 3 3 -- beer bottle, volume 8 3 6 -- beer bottle, color
。
Measurement PropertyID Unit Value 6 'inch' 9 -- cat, tail length 7 'ml' 500 -- beer bottle, volume
。
Trait PropertyID Value 1 'Gone with the Wind' -- book, title 2 'Margaret Mitchell' -- book, author 3 '978-1416548898' -- book, isbn 4 'Phoebe' -- cat, name 5 'Gray' -- cat, color 8 'Green' -- beer bottle, color
编辑:
杰弗里提出了一个有效的观点(见评论),所以我会扩大答案。
该模型允许使用任何types的属性dynamic(即时)创build任何数量的实体,而无需更改模式。 Hovewer,这种灵活性有一个价格 – 存储和search比平常的表devise更慢,更复杂。
时间是一个例子,但首先,为了让事情变得简单,我将把模型变成一个视图。
create view vModel as select e.EntityId , x.Name as PropertyName , m.Value as MeasurementValue , m.Unit , t.Value as TraitValue from Entity as e join Property as p on p.EntityID = p.EntityID join PropertyType as x on x.PropertyTypeId = p.PropertyTypeId left join Measurement as m on m.PropertyId = p.PropertyId left join Trait as t on t.PropertyId = p.PropertyId ;
从评论中使用Jefferey的例子
with q_00 as ( -- all books select EntityID from vModel where PropertyName = 'object type' and TraitValue = 'book' ), q_01 as ( -- all US books select EntityID from vModel as a join q_00 as b on b.EntityID = a.EntityID where PropertyName = 'publisher country' and TraitValue = 'US' ), q_02 as ( -- all US books published in 2008 select EntityID from vModel as a join q_01 as b on b.EntityID = a.EntityID where PropertyName = 'year published' and MeasurementValue = 2008 ), q_03 as ( -- all US books published in 2008 not discontinued select EntityID from vModel as a join q_02 as b on b.EntityID = a.EntityID where PropertyName = 'is discontinued' and TraitValue = 'no' ), q_04 as ( -- all US books published in 2008 not discontinued that cost less than $50 select EntityID from vModel as a join q_03 as b on b.EntityID = a.EntityID where PropertyName = 'price' and MeasurementValue < 50 and MeasurementUnit = 'USD' ) select EntityID , max(case PropertyName when 'title' than TraitValue else null end) as Title , max(case PropertyName when 'ISBN' than TraitValue else null end) as ISBN from vModel as a join q_04 as b on b.EntityID = a.EntityID group by EntityID ;
这看起来很复杂,但仔细观察,你可能会注意到CTE的模式。
现在假设我们有一个标准的固定模式devise,其中每个对象属性都有自己的列。 该查询将如下所示:
select EntityID, Title, ISBN from vModel WHERE ObjectType = 'book' and PublisherCountry = 'US' and YearPublished = 2008 and IsDiscontinued = 'no' and Price < 50 and Currency = 'USD' ;
我不打算回答,但现在接受的答案有一个非常糟糕的主意。 关系数据库不应该用来存储简单的属性值对。 这将导致很多问题。
处理这个问题的最好方法是为每种types创build一个单独的表格。
Product ------- ProductId Description Price (other attributes common to all products) Book ---- ProductId (foreign key to Product.ProductId) ISBN Author (other attributes related to books) Electronics ----------- ProductId (foreign key to Product.ProductId) BatteriesRequired etc.
每一张桌子的每一行都应该代表一个关于现实世界的命题,桌子的结构和它们的约束应该反映出被performance的现实。 越接近这个理想,数据越干净,报告和以其他方式扩展系统就越容易。 它也将运行更有效。
你可以使用无模式的方法:
将元数据保存在TEXT列中作为JSON对象(或者其他序列化,但是由于很快解释的原因,JSON更好)。
这种技术的优点:
-
更less的查询:您可以在一个查询中获得所有信息,无需“定向”查询(获取元元数据)和连接。
-
您可以随时添加/删除任何您想要的属性,无需更改表(这在某些数据库中是有问题的,例如,Mysqllocking了表,并且需要很长的时间处理巨大的表)
-
既然是JSON,你不需要在你的后端进行额外的处理。 您的网页(我假设它是一个Web应用程序)只是从您的Web服务读取JSON,就是这样,您可以使用JavaScript的JSON对象,不过你喜欢。
问题:
-
可能浪费的空间,如果你有100本同一作者的书,那么所有书只有author_id的作者表是更经济的空间明智的。
-
需要实现索引。 因为你的元数据是一个JSON对象,所以你没有索引。 但是为您需要的特定元数据实现特定的索引是相当容易的。 例如,你想按作者索引,所以你创build一个author_id和表author_id和item_id,当有人search作者,你可以查找这个表和项目本身。
根据规模,这可能是一个矫枉过正。 在较小规模的联接将工作得很好。
产品应该打字。 例如在产品表中包含type_id,指向您将支持的产品类别,并让您知道要查询哪些其他表以查找适当的相关属性。
在这类问题中,你有三个select:
- 用“通用”列创build一个表。 例如,如果您同时销售书籍和烤面包机,您的烤面包机可能没有ISBN和标题,但它们仍然有某种产品标识和说明。 所以给字段一般的名称,如“product_id”和“description”,书籍的product_id是一个ISBN,烤面包机的制造商的零件号码等。
当真实世界的实体都以相同的方式处理时,至less在大多数情况下都是如此,因此,即使不是“相同”的数据,也必须有至less一个一致的数据。 当存在真正的function差异时,这会被打破。 就像烤面包机,我们计算瓦特=伏特*安培数,可能没有相应的书本计算。 当你开始创buildpages_volts字段,其中包含书的页数和电烤炉的电压时,事情就会失去控制。
-
使用像Damirbuild议的财产/价值计划。 看到我的评论在他的职位的利弊在那里。
-
我通常会build议的是一种types/子types的scheme。 创build一个包含types代码和通用字段的“产品”表。 然后,对于每种真实types(书籍,烤面包机,猫,等等),都会创build一个与产品表连接的独立表格。 那么当你需要做特定书本的处理时,处理书本表。 当您需要进行通用处理时,请处理产品表。