Php 处理身份困境

Php 处理身份困境,php,node.js,database,api,web-services,Php,Node.js,Database,Api,Web Services,关于状态字段和类似的预定义值集,经常会出现问题 让我们以一个订单系统为例,该订单实体的状态可以是新的、进行中的、已支付的等等 问题是: 订单的状态需要为 存储(在数据库中) 已处理(在后端) 通信(在web服务API中传输到前端) 如何在保持以下状态的同时进行这三项活动: 保留状态的含义 高效存储 以下是一些示例实现及其优缺点: 1-状态表 数据库将包含一个id为name的状态表 订单表引用状态的id CREATE TABLE `status` ( `id` INT NOT NUL

关于状态字段和类似的预定义值集,经常会出现问题

让我们以一个订单系统为例,该订单实体的状态可以是新的、进行中的、已支付的等等

问题是: 订单的状态需要为

  • 存储(在数据库中)
  • 已处理(在后端)
  • 通信(在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);
    
  • 后端代码有一个枚举,该枚举在代码中赋予这些预定义整数一个含义

    enum Status {
        PAID = 7;
    };
    
    // While processing as action ...
    order.status = Status::PAID;
    
  • web服务API将返回状态号

    order: { id: 1, status_id: 7 }
    
  • 前端代码有一个类似的枚举,它在代码中赋予这些预定义整数一个含义。(与后端代码类似)

  • 优点:

    • 数据库定义良好并规范化
  • 缺点:
    • 状态编号和含义之间的映射在三个位置完成,这为定义特定状态编号含义时的人为错误和不一致性提供了空间
    • API返回的数据不是描述性的,因为
      status\u id:7
      没有提供具体的含义,因为它不包括
      status\u id:7
2-状态枚举
  • 在数据库中,订单表将包含一个包含预定义状态的ENUM类型的状态列

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

    enum Status {
        PAID = 'PAID'
    };
    
    enum Status {
        PAID = 'PAID'
    };
    

    用作下列用途

    // While processing as action ...
    order.status = Status::PAID;
    
    // While processing as action ...
    order.status = Status::PAID;
    
  • web服务API将返回状态常量

    order: { id: 1, status: 'PAID' }
    
    order: { id: 1, status: 'PAID' }
    
  • 对于预定义的状态常量,前端代码将具有类似的构造。(与后端代码类似)

  • 优点:

    • 数据库定义良好并规范化
    • API返回的数据是描述性的,并提供所需的含义
    • 使用的状态常数已经包含了它们的含义,这减少了出错的机会
  • 缺点:
    • 对数据库中的列使用枚举类型有其局限性。稍后使用ALTER命令向该枚举添加新的状态常量非常昂贵,特别是对于像
      order
      table这样的大型表
3-我提出的解决方案:
  • 数据库将包含一个状态表,其中一个字段名为
    key
    ,类型为string,是该表的主键

    CREATE TABLE `status` (
      `key` VARCHAR(45) NOT NULL,
      PRIMARY KEY (`key`));
    
  • 订单表将包含一个名为
    status
    的字段,其类型字符串引用
    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);
    
  • 后端代码具有常量值作为预定义状态的代码工件

    enum Status {
        PAID = 'PAID'
    };
    
    enum Status {
        PAID = 'PAID'
    };
    

    用作下列用途

    // While processing as action ...
    order.status = Status::PAID;
    
    // While processing as action ...
    order.status = Status::PAID;
    
  • web服务API将返回状态常量

    order: { id: 1, status: 'PAID' }
    
    order: { id: 1, status: 'PAID' }
    
  • 对于预定义的状态常量,前端代码将具有类似的构造。(与后端代码类似)

  • 优点:

    • 数据库定义良好并规范化
    • API返回的数据是描述性的,并提供所需的含义
    • 使用的状态常数已经包含了它们的含义,这减少了出错的机会
    • 使用状态表中的INSERT命令添加新的状态常量非常简单
  • 缺点:
我想知道这是一个可行的解决方案,还是对于这个反复出现的问题有更好的解决方案。 请说明建议的解决方案不好的原因以及更好的解决方案更好的原因
谢谢。

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

  • 我在
    orders
    表中添加了一个类型为
    string
    的列
    status
  • 定义类中所有状态的常量,以便轻松引用它们
  • 在创建订单时制定一个验证规则,使状态值位于您之前定义的唯一允许值中
  • 这使得只需编辑代码库就可以很容易地添加新状态,并且状态的检索值仍然是一个字符串(描述性)

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

    我建议:

  • 以状态(未签名的tinyint,char(5))存储在数据库中
  • Id必须是2:1,2,4,8
  • 后端代码const name必须人性化,但value--int:
    const PAID=2
  • 在后端,您不应该直接使用常量,而应该使用状态类对象,它将包含一些方法,如
    value
    name
  • 这个类的测试将检查它的所有值是否都以DB为单位,并且所有DB的值都被类覆盖
  • 人为失误的空间

    为避免人为错误而发明的测试

    状态通常并不复杂,也没有太多的值来处理它们

    Enum是邪恶的

    关于你的提议:

    数据库定义良好并规范化

    不,它是非规范化的

    API返回的数据是描述性的,并提供所需的含义

    您始终可以使用包装器,它进入状态表以获取人名

    使用的状态常数已经包含了它们的含义,这减少了出错的机会

    常量名称用于人类,值用于折弯机

    使用状态表中的INSERT命令添加新的状态常量非常简单


    第1个和我的解决方案也是一样。

    很好,但DB将允许任何处于
    状态的字符串
    ,并且DB既没有关于pos的信息也没有约束