将复合主键重构为Rails的简单键?

时间:2016-12-13 23:58:29

标签: sql ruby-on-rails database database-design refactoring

我的应用程序使用Ruby on Rails ActiveRecord模型,如果不安装第三方gem(例如 composite-primary-keys ),则不允许使用复合键。有没有办法可以将复合键重构成一个简单的键,这样它就适合这个范例,或者我应该咬一口并安装宝石?

我还处于早期设计阶段,所以我没有需要担心的数据,我希望尽可能保持对Rails习语的忠诚。

我正在创建一个配方数据库,可以逐步列出成分和说明。数据库模式类似于下面显示的模式,并在Recipe_Steps和Recipe_Step_Ingredients表(图像的底部中心)中使用复合键。

Database schema

1 个答案:

答案 0 :(得分:0)

你很可能过度思考并使问题过于复杂。坚持使用名为id的单个主键的AR惯用语。

对于连接表,使用外键而不是复合PK。同时坚持命名惯例,除非你想通过违反最小惊喜的原则看起来无能为力或惹恼其他开发者。这意味着:

  • 使用snake_case表示所有内容(表名,列,索引名等)
  • 不要在列前加上表名。它只会使应用程序中的每个变量更长,而在ORM中则不需要。
  • _id用于外键列。前; parent_id
  • 使用_at作为时间戳。前; confirmed_at
  • thing_other_things用于连接表,除非有更具描述性的名称

这些情况中的许多情况也应该使用间接关系来连接层次结构而不是复制外键。

这是一个示例数据库架构:

ActiveRecord::Schema.define(version: 20161214013752) do

  # These are extensions that must be enabled in order to support this database
  enable_extension "plpgsql"

  create_table "ingredient_types", force: :cascade do |t|
    t.string   "name"
    t.string   "description"
    t.datetime "created_at",  null: false
    t.datetime "updated_at",  null: false
  end

  create_table "ingredients", force: :cascade do |t|
    t.integer  "ingredient_type_id"
    t.datetime "created_at",         null: false
    t.datetime "updated_at",         null: false
    t.index ["ingredient_type_id"], name: "index_ingredients_on_ingredient_type_id", using: :btree
  end

  create_table "recipe_ingredients", force: :cascade do |t|
    t.integer  "recipe_id"
    t.integer  "ingredient_id"
    t.float    "quantity"
    t.datetime "created_at",    null: false
    t.datetime "updated_at",    null: false
    t.index ["ingredient_id"], name: "index_recipe_ingredients_on_ingredient_id", using: :btree
    t.index ["recipe_id"], name: "index_recipe_ingredients_on_recipe_id", using: :btree
  end

  create_table "steps", force: :cascade do |t|
    t.integer  "recipe_id"
    t.integer  "ordinal"
    t.text     "instruction"
    t.datetime "created_at",   null: false
    t.datetime "updated_at",   null: false
    t.index ["recipe_id"], name: "index_steps_on_recipe_id", using: :btree
  end

  create_table "recipes", force: :cascade do |t|
    t.string   "name"
    t.string   "description"
    t.datetime "created_at",  null: false
    t.datetime "updated_at",  null: false
  end

  add_foreign_key "ingredients", "ingredient_types"
  add_foreign_key "recipe_ingredients", "ingredients"
  add_foreign_key "recipe_ingredients", "recipes"
  add_foreign_key "steps", "recipes"
end
class IngredientType < ApplicationRecord
  has_many :ingredients
end

class Ingredient < ApplicationRecord
  belongs_to :ingredient_type
  has_many :recipe_ingredients
  has_many :recipes, through: :recipe_ingredients
end

class RecipeIngredient < ApplicationRecord
  belongs_to :recipe
  belongs_to :ingredient
  has_one :ingredient_type, through: :ingredient
end

class Step < ApplicationRecord
  belongs_to :recipe
end

class Recipe < ApplicationRecord
  has_many :recipe_ingredients
  has_many :ingredients, through: :recipe_ingredients
  has_many :steps
end
相关问题