我有一张桌子。一个包含25列的大表,每个列包含关于特定实体的原子数据。具体地说,实体是待售的房地产(如房间和房屋),因此表称为财产。
每个属性都有一个子类(实际上它被称为“类型”,但我们将其称为“子类”以避免与数据类型混淆),此时该子类是“已建待售”或“在建,但可以投资”。它还有很多属性,如地址、价格等,其中大部分是在子类之间共享的,但有些则不是。属性有不同的数据类型,它们是:
整数
浮点数
短文本行
长文本
其他表的外键
这些“其他表格”用于从版主可编辑的选项列表(如城市区域列表、建筑公司列表等)中进行选择。
版主应该能够创建新属性并对其进行编辑。用户应该能够查看特定属性的详细信息,并搜索满足特定条件的属性,然后将其视为一个表,按列之一排序。
根据属性的子类,只有属性属性的子集可供用户查看和版主编辑。此外,根据数据类型的不同,需要使用不同的html代码向用户显示这些属性,并为版主提供编辑控件,以及在编辑后执行不同的数据验证检查。
字段列表不是动态的—列列表及其显示方式不太可能经常更改,而且版主也不需要更改它。
但是,由于25是一个相当大的数字,我想将所有关于属性表的元数据组织在一个地方:关于哪些子类是列的信息,以及如何显示、编辑和验证数据的信息。能够以某种简单的方式(如数组)从我的代码访问所有这些元数据将是一件好事。我看到有三种选择:
1。常数php数组
只需创建一个php文件或函数来构造包含元数据的数组,然后在需要时包含/调用它。
赞成的意见:
很简单。
快。
欺骗:
很难维护,因为php代码过于冗长和丑陋。
2。mysql数据库
在数据库中创建一个表属性并将元数据存储在其中。新表将包含属性表中的列名、此列中的数据与每个属性子类的相关性、预期的数据类型等。然后创建一个函数,该函数将查询必要的字段并将结果数据作为数组返回。
赞成的意见:
更容易更改元数据。
需要维护的代码更少。
以后可以对其进行扩展,以允许用户更改列列表。从属性表中添加或删除列不会有太大问题。尽管在我看来,用户能够动态地更改数据库模式是一种严重的代码味道。如果我错了就纠正我。
欺骗:
无论何时更改元数据,都必须相应地更新服务器数据库。但它只会在数据库模式改变时发生,所以没人在意。
速度较慢-除了创建阵列的成本,这将增加与服务器对话的成本和从数据库中选择数据的成本。尽管后者可能被mysql查询缓存机制否定。
三。将属性及其属性分隔到不同的表中
按照上述解决方案创建元数据表,只将其命名为property_attribute。还可以使用property和property_属性的外键创建property_数据表,并为属性值多创建一列。属性表将只包含主键和子类,而实际的属性值只能通过带有两个连接的查询来检索。
赞成的意见:
最灵活的解决方案。如果属性列表被更改,数据库架构将保持不变。
欺骗:
每个属性数据行将包含未知类型的单个数据。要么将它们全部存储为文本或blob,要么为单独的数据类型创建单独的列。两种解决方案看起来都很糟糕。
目前还不清楚如何处理属性表中以前的外键。在每次插入时进行的自动数据完整性检查几乎是不可能的(可能有触发器?我不确定)。
选择数据将变得更加困难。数据将以property_id
-property_attribute_id
-value
三位一体的形式获取,这不直观,需要更多的努力才能正确输出。
除此之外,按一个或多个属性进行筛选和排序将把我送到受伤害的世界。
非常非常慢。
感觉就像用直升机过马路。
坦白说,我不喜欢这两种解决方案。但在我看来,第二个最丑。你怎么认为?
最佳答案
我要问你的第一个问题是:你是在寻求帮助设计一个合适的数据库模式,还是在询问如何在代码中处理这些属性/子类?
数据库架构
数据库模式并不是我的专长,所以我将把它留给比我更了解的人。
不过,我可能只需要在一个属性表中将每个字段作为自己的列,因为这样做很简单,而且可以让您正确地索引每个字段。正如你所说,新字段不会经常添加。
用php处理
在我看来,将这些字段看作元数据是错误的。每个子类都有自己的字段集,这意味着从技术上说它们都是独立的实体。
为了清楚起见,我将保持这一点,但以下是我将要做的事情:
为每种属性类型创建一个popo(普通的ole'php对象),这些只是值对象,类似于orm中的内容。与doctrine2实体一样,它们不执行任何类型的持久性。
我在这里简化这个例子。这绝对不遵循srp,是一个糟糕的设计i.m.o,但我这样写是为了简洁。
创建一个工厂类,负责从数据库中获取和保存数据,设置适当的popo并相应地填充数据。
这就是它的全部。这是一个小虫子。如果你想的话,你可以用一个适当的orm来消除2。
它们的关键是为每个属性子类拥有单独的对象。这是有利的,因为:
由于每个属性类型都有自己的类和自己的预定义属性集(以及getter/setter),因此您不必担心填充或使用属于其他属性类型的数据。
它提供了一个明确的区别,您可以使用它来呈现特定于每个属性类型的模板。(不是说你以前做不到…我只是觉得这样比较干净。)
每个属性类型类都可以从基类继承,以容纳属性类型之间通用的所有字段。