5

我有一张桌子。一个有 25 列的大表,每列都包含有关特定实体的原子数据。实体具体来说是待售的房地产(如房间和房屋),因此该表称为property

每个属性都有一个子类(实际上称为“类型”,但我们将其称为“子类”以避免与数据类型混淆),此时它是“已建成并出售”或“正在建设中,但可以投资”。它还有很多属性,比如地址、价格等,其中大部分是子类之间共享的,但也有一些不是。属性有不同的数据类型,它们是:

  • 整数
  • 浮点数字
  • 短行文本
  • 长长的文本块
  • 其他表的外键

这些“其他表格”用于从主持人可编辑的选项列表中进行选择(如市区列表、建筑公司列表等)。

版主应该能够创建新属性并对其进行编辑。用户应该能够查看特定属性的详细信息并搜索满足特定条件的属性,然后将它们作为表格查看,可按其中一列排序。

根据属性的子类,只有属性属性的子集可供用户查看和版主进行编辑。此外,根据数据类型,需要不同的 HTML 代码向用户显示这些属性并为版主提供编辑控件,以及在编辑后应执行不同的数据验证检查。

字段列表不是动态的 - 列列表及其显示方式不太可能经常更改,主持人也不需要更改它。

但是,由于 25 是一个相当大的数字,我想将有关属性表的所有元数据组织并保存在一个地方:关于哪些子类是列的信息以及应如何显示、编辑和验证数据的信息。如果能够以某种简单的方式(如数组)从我的代码中访问所有这些元数据,那就太好了。我看到三个选项可以做到这一点:


1.常量PHP数组

只需创建一个 PHP 文件或函数,它将使用元数据构造数组,然后在需要时包含/调用它。

优点:

  • 简单的。
  • 快速地。

缺点:

  • 由于过于冗长和丑陋的 PHP 代码,更难维护。

2. MySQL数据库

在数据库中创建一个表property_meta并将元数据存储在那里。新表将包含属性表中的列名、该列中的数据与每个属性子类的相关性、预期的数据类型等。然后创建一个函数,该函数将查询必要的字段并将结果数据作为数组返回。

优点:

  • 更容易更改元数据。
  • 需要维护的代码更少。
  • 以后可以扩展它以允许用户更改列列表。在属性表中添加或删除列不会有太大问题。尽管在我看来,用户能够即时更改数据库架构是一种严重的代码异味。如我错了请纠正我。

缺点:

  • 每当元数据发生变化时,服务器数据库都必须相应地更新。但它只会在数据库模式发生变化时发生,所以没人关心。
  • 较慢 - 创建数组的成本将增加与服务器通信的成本以及从数据库中选择数据的成本。尽管后者很可能被 MySQL 查询缓存机制所否定。

3. 将属性及其属性分开到不同的表中

按照上述解决方案创建元数据表,仅将其命名为property_attribute还使用propertyproperty_attribute的外键创建property_data表,以及属性值的另一列。属性表将只包含主键和子类,而实际属性值只能通过具有两个连接的查询来检索。

优点:

  • 最灵活的解决方案。如果属性列表发生更改,数据库模式将保持不变。

缺点:

  • 每个property_data行将包含一条未知类型的数据。要么将它们全部存储为 TEXT 或 BLOB,要么为单独的数据类型创建单独的列。这两种解决方案看起来都很难看。
  • 目前还不清楚如何处理属性表中的前外键。在每次插入时进行的自动数据完整性检查几乎是不可能的(也许可以使用触发器?我不确定)。
  • 选择数据将变得更加困难。数据会被取为property_id——三位一体property_attribute_idvalue不直观,需要付出更多努力才能正确输出。
  • 不仅如此,按一个或多个属性进行过滤和排序会将我带到受伤的世界。
  • 非常非常慢。
  • 感觉就像用直升机过马路。

坦率地说,我不喜欢这两种解决方案。但在我看来,第二个是最不丑的。你怎么看?

4

2 回答 2

2

我对您的第一个问题是:您是在寻求帮助设计适当的数据库模式,还是在询问如何在代码中处理这些属性/子类?

数据库模式

数据库模式并不完全是我的强项,所以我将把它留给可能比我更了解的人。
我可能只是在单个属性表中将每个字段作为其自己的列,因为它很容易并且可以让您正确索引每个字段。正如您所说,不会经常添加新字段。

在 PHP 中处理它

在我看来,将这些字段视为元数据是错误的。每个子类都有自己的一组字段,这意味着从技术上讲,它们都是不同类型的实体。

为了清楚起见,我保持简单,但这是我要做的事情:

  1. 为每种属性类型创建一个 POPO(普通 ole' php 对象)。
    这些只是值对象,类似于您在 ORM 中可能找到的对象。像 Doctrine2 实体一样,它们不执行任何类型的持久性。

  2. 这是我简化示例的地方..这绝对不遵循 SRP 并且是糟糕的设计 imo,但为了简洁起见,我以这种方式编写它。

    创建一个工厂类,负责从/向数据库获取和保存数据,实例化适当的 POPO 并相应地填充数据。

这就是它的全部。这是一个迷你 ORM。如果您愿意,您实际上可以取消 #2 并使用适当的 ORM...

他们的关键是为每个属性子类提供单独的对象。这是有利的,因为:

  • 由于每个属性类型都有自己的类和自己的预定义属性集(和 getter/setter),因此您不必担心填充或使用属于其他属性类型的数据。
  • 它提供了一个明确的区别,您可以使用它来呈现特定于每个属性类型的模板。(并不是说你以前不能这样做......我只是觉得这种方式更干净。)
  • 每个属性类型类都可以从一个基类继承,以容纳属性类型中通用的所有字段。
于 2012-08-29T18:16:23.463 回答
1

我看到了另一种选择,除了 MySQL 之外,您还可以考虑使用 NoSQL,但您需要认真考虑您的要求,以便在两者之间做出正确的产品选择

  • 列店/列族
  • 文档存储
  • 核心价值
  • ...和更多

最大的好处之一是灵活的数据模型,但是 NoSQL 和关系数据库各有优缺点,因此在决定使用 nosql 解决方案之前,您必须了解该产品

于 2012-08-29T18:31:19.133 回答