处理现状困境

Mee*_*ons 20 php database api web-services node.js

关于状态字段和类似的预定义值集存在重复出现的问题.

让我们举一个订单系统的例子,订单实体的状态可以是New,In Progress,Paid等.

问题:

订单的状态需要

  • 存储(在数据库中)
  • 处理(在后端)
  • 传达(到Web服务API的前端)

如何保持这三项活动:

  • 保留状态的含义.
  • 高效存储.

以下是一些具有优缺点的示例实现:

1-状态表

  • 数据库将包含一个id为name的状态表
  • 订单表引用状态的ID.

    CREATE TABLE `status` (
      `id` INT NOT NULL,
      `name` VARCHAR(45) NOT NULL,
      PRIMARY KEY (`id`));
    
    CREATE TABLE IF NOT EXISTS `order` (
      `id` INT NOT NULL AUTOINCREMENT,
      `status_id` INT NOT NULL,
      PRIMARY KEY (`id`),
      INDEX `order_status_idx` (`status` ASC),
      CONSTRAINT `order_status_id`
        FOREIGN KEY (`status_id`)
        REFERENCES `status` (`id`)
        ON DELETE NO ACTION
        ON UPDATE NO ACTION);
    
    Run Code Online (Sandbox Code Playgroud)
  • 后端代码有一个枚举,它为代码中的这些预定义整数赋予了意义

    enum Status {
        PAID = 7;
    };
    
    // While processing as action ...
    order.status = Status::PAID;
    
    Run Code Online (Sandbox Code Playgroud)
  • Web服务API将返回状态编号

    order: { id: 1, status_id: 7 }
    
    Run Code Online (Sandbox Code Playgroud)
  • 前端代码具有类似的枚举,它为代码中的这些预定义整数赋予了含义.(比如后端代码)

  • 优点:

    • 数据库定义良好并规范化
  • 缺点:
    • 状态编号和含义之间的映射在三个位置完成,这为人为错误提供了空间,并且在定义特定状态编号的含义时不一致.
    • 来自API的返回数据不具有描述性,因为status_id: 7它没有提供具体含义,因为它不包含的含义status_id: 7

2-状态ENUM

  • 在数据库中,订单表将包含状态列,其类型为ENUM,包含预定义的状态.

    CREATE TABLE IF NOT EXISTS `order` (
      `id` INT NOT NULL AUTOINCREMENT,
      `status` ENUM('PAID') NULL,
      PRIMARY KEY (`id`));
    
    Run Code Online (Sandbox Code Playgroud)
  • 后端代码具有常量值作为预定义状态的代码工件

    enum Status {
        PAID = 'PAID'
    };
    
    Run Code Online (Sandbox Code Playgroud)

    要么

    class Status {
    public:
        static const string PAID = PAID;
    };
    
    Run Code Online (Sandbox Code Playgroud)

    用作以下内容

    // While processing as action ...
    order.status = Status::PAID;
    
    Run Code Online (Sandbox Code Playgroud)
  • Web服务API将返回状态常量

    order: { id: 1, status: 'PAID' }
    
    Run Code Online (Sandbox Code Playgroud)
  • 前端代码将具有用于预定义状态常量的类似构造.(比如后端代码)

  • 优点:

    • 数据库定义良好并规范化
    • API返回的数据是描述性的,并提供所需的含义.
    • 使用的状态常量已包含其含义,可减少出错的可能性.
  • 缺点:
    • 对数据库中的列使用ENUM类型有其局限性.稍后使用ALTER命令向该枚举添加新的状态常量对于像order表这样的大表来说是特别昂贵的.

3-我提出的解决方案:

  • 数据库将包含一个状态表,其中一个字段key使用类型字符串调用,该字符串是此表的主键.

    CREATE TABLE `status` (
      `key` VARCHAR(45) NOT NULL,
      PRIMARY KEY (`key`));
    
    Run Code Online (Sandbox Code Playgroud)
  • 订单表将包含一个名为statustype string的key字段,该字段引用status表的字段.

    CREATE TABLE IF NOT EXISTS `order` (
      `id` INT NOT NULL AUTOINCREMENT,
      `status` VARCHAR(45) NOT NULL,
      PRIMARY KEY (`id`),
      INDEX `order_status_idx` (`status` ASC),
      CONSTRAINT `order_status`
        FOREIGN KEY (`status`)
        REFERENCES `status` (`key`)
        ON DELETE NO ACTION
        ON UPDATE NO ACTION);
    
    Run Code Online (Sandbox Code Playgroud)
  • 后端代码具有常量值作为预定义状态的代码工件

    enum Status {
        PAID = 'PAID'
    };
    
    Run Code Online (Sandbox Code Playgroud)

    要么

    class Status {
    public:
        static const string PAID = PAID;
    };
    
    Run Code Online (Sandbox Code Playgroud)

    用作以下内容

    // While processing as action ...
    order.status = Status::PAID;
    
    Run Code Online (Sandbox Code Playgroud)
  • Web服务API将返回状态常量

    order: { id: 1, status: 'PAID' }
    
    Run Code Online (Sandbox Code Playgroud)
  • 前端代码将具有用于预定义状态常量的类似构造.(比如后端代码)

  • 优点:

    • 数据库定义良好并规范化
    • API返回的数据是描述性的,并提供所需的含义.
    • 使用的状态常量已包含其含义,可减少出错的可能性.
    • 使用状态表中的INSERT命令添加新的状态常量很简单.
  • 缺点:
    • ???

我想知道这是否是一个可行的解决方案,或者对于这个反复出现的问题有更好的解决方案.

请说明为什么建议的解决方案不好以及为什么更好的解决方案更好的原因

谢谢.

Ram*_*mer 1

这是我解决这个问题的方法:

  1. 我在表中添加了一个status带有类型的列。stringorders
  2. 定义班级中所有状态的常量,以便您可以轻松引用它们。
  3. 在创建订单时制定验证规则,确保状态值位于您之前定义的唯一允许的值中。

这使得只需编辑代码库即可轻松添加新状态,并且状态的检索值仍然是字符串(描述性)。

我希望这能回答你的问题。

  • 我认为这不是什么大问题,因为您不应该直接与数据库层进行任何交互(尤其是创建记录);应该始终有一个应用程序逻辑层来从数据库中检索、创建、更新或删除。 (2认同)