草庐IT

php - 处理状态困境

coder 2023-05-29 原文

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

让我们以一个带有订单实体的订单系统为例,该实体的状态可能是“新建”,“进行中”,“已付款”等。

问题:

订单状态必须为

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

  • 如何保持以下三项 Activity :
  • 保留状态的含义。
  • 有效的存储。

  • 以下是一些示例实现及其优缺点:

    1-状态表
  • 该数据库将包含一个ID为ID名为
  • 的状态表
  • 订单表引用状态的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_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`));
    
  • 后端代码具有恒定值,作为预定义状态的代码工件
    enum Status {
        PAID = 'PAID'
    };
    

    或者
    class Status {
    public:
        static const string PAID = PAID;
    };
    

    用作追随者
    // While processing as action ...
    order.status = Status::PAID;
    
  • Web服务API将返回状态常量
    order: { id: 1, status: 'PAID' }
    
  • 前端代码将具有类似的预定义状态常量构造。 (如后端代码)
  • 优点:
  • 数据库定义良好且已规范化
  • 从API返回的数据是描述性的,并具有所需的含义。
  • 使用的状态常量已经包含其含义,这减少了出错的机会。
  • 缺点:
  • 对数据库中的列使用ENUM类型有其局限性。稍后使用ALTER命令向该枚举添加新的状态常量非常昂贵,特别是对于像order表这样的大型表。

  • 3-我建议的解决方案:
  • 数据库将包含一个状态表,该状态表包含一个名为key的字段,其类型为string,这是该表的主键。
    CREATE TABLE `status` (
      `key` VARCHAR(45) NOT NULL,
      PRIMARY KEY (`key`));
    
  • 订单表将包含一个名为status的字段,其类型为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);
    
  • 后端代码具有恒定值,作为预定义状态的代码工件
    enum Status {
        PAID = 'PAID'
    };
    

    或者
    class Status {
    public:
        static const string PAID = PAID;
    };
    

    用作追随者
    // While processing as action ...
    order.status = Status::PAID;
    
  • Web服务API将返回状态常量
    order: { id: 1, status: 'PAID' }
    
  • 前端代码将具有类似的预定义状态常量构造。 (如后端代码)
  • 优点:
  • 数据库定义良好且已规范化
  • 从API返回的数据是描述性的,并具有所需的含义。
  • 使用的状态常量已经包含其含义,这减少了出错的机会。
  • 使用状态表中的INSERT命令添加新的状态常数很简单。
  • 缺点:
  • ???

  • 我想知道这是否是可行的解决方案,还是针对此重复出现的问题有更好的解决方案。

    请说明提出的解决方案不好的原因,以及为什么您提供更好的解决方案更好的原因

    谢谢你。

    最佳答案

    这是我针对这个问题的方法:

  • 我在status表中添加了string列,其类型为orders
  • 定义类中所有状态的常量,以便您轻松引用它们。
  • 创建一个验证规则,以创建状态值在您之前定义的唯一允许的值中的顺序。

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

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

    关于php - 处理状态困境,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49277503/

    有关php - 处理状态困境的更多相关文章

    1. ruby - 在 Ruby 程序执行时阻止 Windows 7 PC 进入休眠状态 - 2

      我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0

    2. ruby - 如何指定 Rack 处理程序 - 2

      Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

    3. ruby-on-rails - 跳过状态机方法的所有验证 - 2

      当我的预订模型通过rake任务在状态机上转换时,我试图找出如何跳过对ActiveRecord对象的特定实例的验证。我想在reservation.close时跳过所有验证!叫做。希望调用reservation.close!(:validate=>false)之类的东西。仅供引用,我们正在使用https://github.com/pluginaweek/state_machine用于状态机。这是我的预订模型的示例。classReservation["requested","negotiating","approved"])}state_machine:initial=>'requested

    4. ruby - 字符串文字中的转义状态作为 `String#tr` 的参数 - 2

      对于作为String#tr参数的单引号字符串文字中反斜杠的转义状态,我觉得有些神秘。你能解释一下下面三个例子之间的对比吗?我特别不明白第二个。为了避免复杂化,我在这里使用了'd',在双引号中转义时不会改变含义("\d"="d")。'\\'.tr('\\','x')#=>"x"'\\'.tr('\\d','x')#=>"\\"'\\'.tr('\\\d','x')#=>"x" 最佳答案 在tr中转义tr的第一个参数非常类似于正则表达式中的括号字符分组。您可以在表达式的开头使用^来否定匹配(替换任何不匹配的内容)并使用例如a-f来匹配一

    5. ruby - Net::HTTP 获取源代码和状态 - 2

      我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur

    6. ruby-on-rails - 为模型创建状态属性 - 2

      我想为我的Task模型创建一个status属性,该属性将按以下顺序指示它在三部分进度中的位置:打开=>进行中=>完成。它的工作方式类似于亚马逊包裹的交付方式:已订购=>已发货=>已交付。我想知道设置此属性的最佳方法是什么。我可能是错的,但创建三个独立的bool属性似乎有点多余。实现此目标的最佳方法是什么? 最佳答案 Rails4有一个内置的enummacro.它使用单个整数列并映射到键列表。classOrderenumstatus:[:ordered,:shipped,:delivered]end状态映射如下:{ordered:0,

    7. ruby - 是否可以在不实际发送或读取数据的情况下查明 ruby​​ 套接字是否处于 ESTABLISHED 或 CLOSE_WAIT 状态? - 2

      s=Socket.new(Socket::AF_INET,Socket::SOCK_STREAM,0)s.connect(Socket.pack_sockaddr_in('port','hostname'))ssl=OpenSSL::SSL::SSLSocket.new(s,sslcert)ssl.connect从这里开始,如果ssl连接和底层套接字仍然是ESTABLISHED,或者它是否在默认值7200之后进入CLOSE_WAIT,我想检查一个线程几秒钟甚至更糟的是在实际上不需要.write()或.read()的情况下关闭。是用select()、IO.select()还是其他方法完成

    8. Ruby-vips 图像处理库。有什么好的使用示例吗? - 2

      我对图像处理完全陌生。我对JPEG内部是什么以及它是如何工作一无所知。我想知道,是否可以在某处找到执行以下简单操作的ruby​​代码:打开jpeg文件。遍历每个像素并将其颜色设置为fx绿色。将结果写入另一个文件。我对如何使用ruby​​-vips库实现这一点特别感兴趣https://github.com/ender672/ruby-vips我的目标-学习如何使用ruby​​-vips执行基本的图像处理操作(Gamma校正、亮度、色调……)任何指向比“helloworld”更复杂的工作示例的链接——比如ruby​​-vips的github页面上的链接,我们将不胜感激!如果有ruby​​-

    9. ruby - 在 ruby​​ 中生成一个进程,捕获 stdout,stderr,获取退出状态 - 2

      我想从ruby​​rake脚本运行一个可执行文件,比如foo.exe我希望将foo.exe的STDOUT和STDERR输出直接写入我正在运行rake任务的控制台.当进程完成时,我想将退出代码捕获到一个变量中。我如何实现这一目标?我一直在玩backticks、process.spawn、system但我无法获得我想要的所有行为,只有部分更新:我在Windows上,在标准命令提示符下,而不是cygwin 最佳答案 system获取您想要的STDOUT行为。它还返回true作为零退出代码,这可能很有用。$?填充了有关最后一次system调

    10. ruby - Faye WebSocket,关闭处理程序被触发后重新连接到套接字 - 2

      我有一个super简单的脚本,它几乎包含了FayeWebSocketGitHub页面上用于处理关闭连接的内容:ws=Faye::WebSocket::Client.new(url,nil,:headers=>headers)ws.on:opendo|event|p[:open]#sendpingcommand#sendtestcommand#ws.send({command:'test'}.to_json)endws.on:messagedo|event|#hereistheentrypointfordatacomingfromtheserver.pJSON.parse(event.d

    随机推荐