首页 > 解决方案 > Ruby On Rails - 用于保存 CRUD 操作参数/有效负载的数据库结构

问题描述

我想要的是

我想制作一个表格以将“CRUD 操作信息本身”保存在我的数据库中。

eg)
①<code>新建行{"name": "Tom", "price": 200}
②<code>查找一行 WHERE {"age": 30}
③<code>删除行 WHERE {"name" : "John"}
④<code>更新行 WHERE {"name": "Ted"} SET {"price": 300}

我的想法

为了实现上述目标,我创建了两个模型。

①CrudOperation  
t.string :crud_type # this should be one of CRUD ("create", "read", "update", "delete")  
t.string :target_database   



②CrudOperationParameter  
t.integer :crud_operation_id # reference  
t.string :key  
t.value :value

CrudOperation 有很多 CrudOperationParameter-s。

问题

我的模型似乎运行良好,除了 crud_type 是“更新”。

像那样

①新建行{"name": "Tom", "price": 200}

**CrudOperation**  
id: 1  
crud_type: "create"  
target_database: "XXXX"  

**CrudOperationParameter**  
crud_operation_id: 1  
key: "name"  
value "Tom"  

**Another CrudOperationParameter**  
crud_operation_id: 1  
key: "price"  
value "200"  

但是当涉及到用更新类型注册 CrudOperation 时,就会出现问题。

④更新行 WHERE {"name": "Ted"} SET {"price": 300}

**CrudOperation**  
id: 1  
crud_type: "update"  
target_database: "XXXX"  

**CrudOperationParameter**  
crud_operation_id: 1  
key: "name"  
value "Ted"  

**Another CrudOperationParameter**  
crud_operation_id: 1  
key: "price"  
value "300"  

由于 CrudOperationParameter 只有键值列,我无法确定该 CrudOperationParameter 是用于 UPDATE 语句中的 WHERE 子句还是 SET 子句。

你能教我更好的数据库模式来保存这些数据吗?

标签: ruby-on-railsdatabaseschema

解决方案


你所拥有的基本上是实体属性值模式的半生不熟版本(或反模式,取决于你问的是谁)。

如果我真的必须这样做,我会将其设置为:

class CrudOperation < ApplicationRecord
  has_many :crud_operation_parameters
  accepts_nested_attributes_for :crud_operation_parameters
  enum crud_type: {
    create: "create",
    read: "read", 
    update: "update",
    delete: "delete"
  }

  # Convenience setter that maps a hash of attributes 
  # into a an array of key value attibutes suitible for `accepts_nested_attributes_for`
  # and sets the nested attributes
  # @return [Array]
  def parameters=(hash)
    self.crud_operation_parameters_attributes = hash.map do |key, value|
       {
         key: key,
         value: value
       }
    end
  end
end
class CrudOperationParameter < ApplicationRecord
  belongs_to :crud_operation
end
# 1. create new row {"name": "Tom", "price": 200}
CrudOperation.create!(
  crud_type: :create,
  parameters: { 
    name: "Tom", 
    price: 200
  }
)

# 1. create new row {"name": "Tom", "price": 200}
CrudOperation.create!(
  crud_type: :update,
  parameters: { 
    name: "Tom", 
    price: 200
  }
)


我提到这是一个半生不熟的尝试,因为您缺少 Attribute 表,您可以在其中规范化属性的定义并存储诸如类型信息之类的东西。相反,您的解决方案有一个字符串列,其中包含大量可以非规范化的重复项。

但是现代 RDBMS 系统具有诸如 JSON、JSONB 和 HSTORE 之类的列类型,它们可以用来代替 EAV 来存储不适合给定模式的数据。

与 EAV 不同,您不必将所有属性存储在单个列类型(通常是字符串)中并进行类型转换或创建一组属性表来存储不同类型的属性(例如 StringCrudOperationParameter 和 FloatCrudOperationParameter)。

在 Postgres 上使用 JSONB,我会将其设置为:

# rails g model crud_operation crud_type:string payload:jsonb conditions:jsonb
class CrudOperation < ApplicationRecord
  enum crud_type: {
    create: "create",
    read: "read", 
    update: "update",
    delete: "delete"
  }
end
# 1. create new row {"name": "Tom", "price": 200}
CrudOperation.create!(
  crud_type: :create,
  payload: {
    name: "Tom", 
    price: 200
  }
)

# 2. find a row WHERE {"age": 30}
CrudOperation.create!(
  crud_type: :read,
  conditions: {
    age: 30
  }
)

# 3. delete row WHERE {"name": "John"}
CrudOperation.create!(
  crud_type: :delete,
  conditions: {
    name: "John"
  }
)

# 4. update the row WHERE {"name": "Ted"} SET {"price": 300}
CrudOperation.create!(
  crud_type: :update,
  conditions: {
    name: "John"
  },
  payload: {
    price: 300
  }
)

推荐阅读