允许用户定义自己的自定义类型有什么好方法?

时间:2010-03-03 16:55:04

标签: design-patterns database-design customization

假设您正在设计一个应用程序,根据要求,允许用户灵活地创建自定义类型(用于管理他的数据,无论它是什么)。处理此问题的一种方法是定义一个模式,该模式允许我们使用元数据来定义这些类型。这通常意味着生成的db模式将具有某种存储键/值对(属于类型实例的属性)的方式,其中值部分通常存储为字符串(无论列的基础数据类型如何)。仅此一点就存在许多问题。我已经使用db来读取some frown upon来跟踪键/值对。

我遇到的主要问题是它如何影响查询。例如,假设用户想要创建一个名为Event的类型,其中包含以下列:event_namedescriptionstart_atend_at(日期时间)。使用键/值对,其中所有值都是字符串,使查询对参数值的格式更加敏感;因此,查询两个日期之间的一组事件并不像我们使用实际日期时间列那样简单。

这让我想到了可以容纳自定义类型的替代设计。我想到的第一个我最喜欢的是使用数据库本身来定义这些自定义类型。也就是说,不是创建一组必须定义所有类型的单独的元表,而只是允许用户在数据库中创建/修改自己的表的有限权限(所有这些表都将以他的用户名为前缀:例如usertable-johndoe-album)。我用这种方法看到的最突出的问题是最终可能存在的表的数量。我想知道大多数开源数据库(MySQL,Postgres等)是否对他们可以管理多少表而不受阻碍有严格或实际的限制。也就是说,我知道大多数生产就绪数据库都经过调整以处理数百万条记录,但我不知道它们是否具备处理数十万个表的能力。有谁知道吗?

考虑到允许用户创建自己的类型的要求,您更喜欢键/值对还是利用数据库本身?或者,如果您有其他模式/想法,请描述它。

4 个答案:

答案 0 :(得分:3)

我怀疑你是否会达到最大表限制,因为它们通常受操作系统限制而不是RDBMS限制。然而,有一种称为EAV model的替代建模方法,它基本上是描述自定义实体和关联列(属性)的通用方法。有一些缺点,但听起来它可能非常适合您的需求。

如果您选择自定义表格,我会选择名称空间而不是表格前缀来分隔用户/组特定实体。

答案 1 :(得分:0)

“考虑到允许用户创建自己的类型的要求,”

“你更喜欢键/值对”取决于。在一般情况下,如上所述,可能是一个问题。在添加几个列的特定情况下(在本答案的评论中描述),这是一个明显而简单的解决方案。

“或利用数据库本身”在某种程度上。

“我用这种方法看到的最突出的问题是最终可能存在的表格数量很多”这在很大程度上是不相关的 - 你没有真正的证据表明用户定义类型的数量可能是多少。


当您允许用户添加自己的类型时,您将创建一个框架。不是申请。

你有东西支持你的内置类型。

您拥有支持其他扩展类型的工具和实用程序。

“用户”只是将代码插入到您的框架中。

“但我想要最终用户,而不是程序员才能使用它”。馊主意。平民,非程序员不会创建自己的类型。只有程序员才能理解创建自己类型的概念。

由于您正在创建一个框架,请尝试并简化一些事情,以便程序员可以毫无痛苦地添加自己的类型。

答案 2 :(得分:0)

关于你的第二个想法(假设你创建usertable-johndoe-album时它的结构是底层base-album表的镜像: 我要说的一件事是不要为每个用户创建新表。否则,如果您将来必须更改基础表结构(可能是维护修复),则必须对用户创建的所有表进行相同的更改。你可能能找到一种聪明的方法来自动化这个,但它仍然为更多潜在的麻烦,即IMO打开了大门(不包括对表号的硬性上限)。

我认为metatables是解决这个问题的更好方法。可以自动创建用户定义的类型的视图,这可以简化查询元数据。您可能还想考虑在键/值表中不仅仅包含键和值。拥有userID将允许您按UserID进行索引,这可能有助于解决性能问题。

答案 3 :(得分:0)

允许最终用户创建自己的类型的另一种方法是使用名为aspect programming的东西。

实际上,您创建了许多用户组合的“方面”,以便创建他/她的类型。这些方面通常不是由最终用户创建的,而是由您提供,但是用户可以组合这些方面来创建新类型。

示例:

在数字处理中,您可以将系统中的“对象”连接到物理线路/控制器/仪表。假设一个物体连接到温度计,因此物体显示当前温度。创建对象的类型包含许多方面(对象的类似属性),其中一个方面可以是显示值 - temp的显示。在这种情况下。每次用户想要连接temp。他将实例化该类型的对象并将其配置为连接到物理仪表(使用方面)。

现在,如果最终用户可能想要完成更多工作,那么就说他想添加一个图表来显示温度。对于最后24小时的读数(历史) - 只要有一个方面 - 他可以通过继承前面提到的类型创建一个新类型,并将历史方面添加到新类型。所以他所做的就是创造了一种新型。然后,他可以在实例化temp时使用原始类型而不是使用此新类型。宾语。这允许以非常动态的方式处理类型。