【问题标题】:What's a good approach for allowing users to define their own custom types?允许用户定义自己的自定义类型的好方法是什么?
【发布时间】:2010-03-03 16:55:03
【问题描述】:

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

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

这促使我考虑可以适应自定义类型的替代设计。第一个想到并且我最喜欢的是使用数据库本身来定义这些自定义类型。也就是说,与其创建必须定义所有类型的单独的元表集,不如简单地允许用户在数据库中创建/修改他自己的表(所有这些表都以他的用户名为前缀:例如usertable-johndoe-album)。我在这种方法中看到的最突出的问题是最终可能存在的表的绝对数量。我想知道大多数开源数据库(MySQL、Postgres 等)是否对它们可以不受阻碍地管理多少表有硬性或实际限制。也就是说,我知道大多数生产就绪的数据库都经过调整以处理数百万条记录,但我不知道它们是否能够处理数十万个表。有人知道吗?

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

【问题讨论】:

    标签: design-patterns database-design customization


    【解决方案1】:

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

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

    【讨论】:

    • “我怀疑你会达到最大表限制,因为它们通常受操作系统限制而不是 RDBMS 限制。”这很有帮助。谢谢!
    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

      “鉴于允许用户创建自己的类型的要求,”

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

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

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


      当您允许用户添加他们自己的类型时,您就是在创建一个框架。不是应用程序。

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

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

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

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

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

      【讨论】:

      • 在某些情况下,用户通过元数据定义类型确实有意义。它们通常只不过是一组已定义的命名文本字段,它们是通过(通常)用户友好的 UI 创建的。它们通常用于一些非常具体的业务规则,这是在设计系统时没有人想到的,而且它们可能只使用几个月。对于这些情况,让系统足够灵活地处理这种类型而不是要求程序员创建和编译某些东西会更有意义。
      • 假设有一个 Web 应用程序允许用户管理他们自己的数据,这是一种 PIM。 (这不会是此类应用程序中的第一个。)一个用户想要跟踪他已经阅读或想要阅读的书籍。另一个想跟踪他的联系人;他甚至可能拥有大多数在线通讯录中没有的他关心的特定事实。名单还在继续。很多用户,虽然他们可能不会使用我们的行话,但我认为,可以处理跟踪类型属性的概念。它只不过是创建一个带有列名的电子表格,很多人都会这样做。
      • 添加几列甚至与允许定义自定义类型不在同一领域。对于那个键/值对,你需要做的一切,而且非常非常简单。这样做的“成本”是微观的。另外,请用这些细节更新模糊的问题。
      【解决方案4】:

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

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

      例子:

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

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

      【讨论】:

        猜你喜欢
        • 2020-10-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-08-21
        • 2015-12-13
        相关资源
        最近更新 更多