【问题标题】:Challenge - Keep Code and DB Rows Separate挑战 - 保持代码和数据库行分开
【发布时间】:2009-06-27 02:52:58
【问题描述】:

我们都同意 db 是用于存储的,代码不应该与它紧密耦合。当您将首选项存储在数据库中时,您如何实现这一点。举个例子吧。

假设您正在创建一个小型在线投票。每个投票可以有一个“投票类型”。以下是一些投票类型:

  • 匿名投票
  • 基于 IP 的投票

现在,如果有一个用户创建投票并存储“投票类型”的界面,那么在某些时候您似乎不可避免地将数据库中的某些内容(主键或名称)与执行该操作的代码相关联'匿名投票''基于ip的投票'等

在一个不同但相关的question 中,John Sanders 说这很愚蠢——我完全同意他的观点!为什么连接数据库和代码 - 这是一个坏主意。但是,如果您要存储诸如“投票类型”之类的内容,如何避免它呢?

【问题讨论】:

    标签: design-patterns architecture


    【解决方案1】:

    只需定义一些常量,无论它们是在枚举中还是您的语言支持的任何内容,例如

    enum VoteType { Anon = 1, IP = 2, ... }
    

    在数据库的 Poll 表中有一个带有常量值的投票类型列。如果要在数据库中强制执行参照完整性,请创建一个具有相关值的查找表,否则不要,在这种情况下,这些是只是数据库中的一条不透明数据。

    这里没有比 Poll 表有一个列(例如,标题)更多的耦合。这是您需要存储的民意调查的一个方面,所以只需存储它。

    【讨论】:

    • 这让我很烦......但如果你问我,这已经是最好的了。我很想听到更好的答案(因为我自己也遇到过)。
    • 这也是我在我的所有代码中所得到的。问题是我们与不同的机构共享了我们的代码。当他们安装应用程序时,我们的一些表格最终没有相同的 ID。我在下面的条目中建议了将这个问题最小化的方法
    【解决方案2】:

    代码的数据结构与数据库的结构之间需要有某种联系。为了不混合应用程序代码和数据代码而试图避免这种情况是不值得的 - 您需要以最通用的方式设计代码和数据。这对于某些应用程序(设计一个允许用户设计数据结构的应用程序)可能是必要的,但对于许多其他应用程序来说,这可能不是您想要的——您真的想要查询数据库以了解您的投票表的结构吗?每个有多少列?列的名称是什么?。

    维护一个整洁有序的应用程序的一个好方法是维护一个组件,表格和应用程序代码都从该组件中提取它们的值。

    因此,对于您的示例,您可以设计一个带有一些静态最终字段的 VoteTypes 类。要访问实际进入数据库的值的名称,您的代码将调用

    getAnonVotingTypeName() getIpBasedVotingTypeName() 等等。

    这样,如果名称发生更改,您只需在该类中更改它们(当然,还要更新表中的现有记录)。

    【讨论】:

      【解决方案3】:

      你可以有一个枚举。在 C# 中,类似:

      public enum VoteType
      {
          ANONYMOUS,
          IP_BASED,
          OTHER
      }
      

      然后,在代码中你只需说类似

      switch(vote.Category)
      {
         case VoteType.ANONYMOUS: //do stuff
         case VoteType.IP_BASED: //do some other stuff
         //etc
      }
      

      这比使用基于字符串要好,它避免了一些拼写错误和类似的错误。

      【讨论】:

        【解决方案4】:

        解耦代码和数据的主要原因是在某些时候您可能希望以不同的方式呈现数据。那时,如果您有紧密耦合的代码和数据,您将不得不做很多工作来将其剥离。

        另一个原因是,在文本文件中而不是在数据库中进行代码更改是难以超越的。

        因此,如果您确定演示文稿永远不会改变,并且您知道保持代码最新的简单方法,那么将它们分开确实没有什么大的理由。

        但是,这种情况很少见。

        【讨论】:

          【解决方案5】:

          如果我错了,请纠正我,但你不能在你的Polls table 中存储一个vote_type field 吗?如果 vote_type 是 ip,则使用 storeVoteByIP() 函数。如果是userID,则使用storeVoteByID() 方法 - 或一种带有开关的方法。

          也许我只是天真,但我没有看到这里的挑战:)

          switch($vote_type) {
            case 1:
              #insert_vote_by_ip();
              break;
            case 2:
              #insert_vote_by_userid();
              break;
            ...
          }
          

          我错过了什么?

          【讨论】:

          • 实际上有很多方法可以做到这一点。这个特殊的解决方案的问题是,您正在隐藏 id 'vote_type' 和代码之间的连接,以便在任意代码段中运行。我尝试过的一种方法是让一个类注册“ip”与其连接的事实,然后向知道这一点的管理器注册自己。有关对此的批评,请参阅:我列出了其中三个 stackoverflow.com/questions/1050062/…
          【解决方案6】:

          如果您经常更改偏好/配置(例如您以良好的频率创建新的投票类型),存储偏好/配置可能是一个好主意。

          另一方面,如果新的投票类型对您的模型非常重要(例如,当基于 IP 的投票有一个完整的系统来获取统计信息,或者与之相关的许多业务逻辑时),它们有一定的权利提升为实体、类等。

          但我不认为你可以将数据库与你的代码完全分离,仅仅因为数据库会影响你的源代码(尤其是当你处理事务时)。

          【讨论】:

            【解决方案7】:

            让我们假设您创建了一个类,该类实际上完成了确定 VoteType 应该做什么的艰苦工作(因此它可以检查诸如 is_another_vote_available 之类的内容)等。所以您可以:

            • VoteTypeIpSingleVote:此选项允许每个 IP 地址投一票
            • VoteTypeAnonymous:这个对投票没有限制。

            在数据库中,您将在 VoteType 表中有条目:

            • 1 单 IP 投票
            • 2 匿名

            然后您可以创建一个所有 VoterTypes(VoteTypeAnonymous 等)实现的接口,该接口具有属性“VoteType”,该属性返回任一

            a) 它们关联的行的主键 b) 以散列为主键的枚举类型 c) 通过在设置表中查找找到的主键(这样做的好处是每个人都可以访问数据库和代码之间的连接)

            这种方法的优点是您可以拥有一个管理器类,每个 VoterTypes 都可以在该管理器类中注册(甚至可以使用反射自动注册)。

            所以你可以打电话:

            id = fetchVoteTypeToBeUsedFromDb

            manager.getVoteType(id).is_available(datetime.now())

            这样,新的 VoteTypes 可以通过注册自己而无缝添加,而不必不断更新 switch 语句。

            【讨论】:

              【解决方案8】:

              要做的一件事就是将首选项作为 XML 存储到数据库中的 XML 列中。然后数据库不关心存储了什么 - 由代码来解决。

              【讨论】:

              • 现在,这有什么问题?我之前非常成功地完成了此操作,将首选项序列化到数据库列。我还使用了一个配置源提供程序,它从数据库而不是磁盘文件中获取配置设置。投票者能否提供有关此答案有什么问题的线索?
              猜你喜欢
              • 1970-01-01
              • 2018-01-21
              • 1970-01-01
              • 2013-05-16
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2015-04-09
              • 2016-06-06
              相关资源
              最近更新 更多