:primary_keyと:foreign_keyを同時指定して、主キーではないけど共通なカラム同士で関連付けする
7663 ワード
(Rails + MySQL を想定しています)
↓のような3TBLがあるとする
class CreateAtbl < ActiveRecord::Migration
def change
create_table :atbls do |t|
t.string :name
end
end
end
class CreateBtbl < ActiveRecord::Migration
def change
create_table :btbls do |t|
t.string :name
t.integer :b_a_id # AテーブルのIDを保持
end
end
end
class CreateCtbl < ActiveRecord::Migration
def change
create_table :ctbls do |t|
t.string :name
t.integer :c_a_id # AテーブルのIDを保持
end
end
end
class Atbl < ActiveRecord::Base
has_many :btbls, foreign_key: "b_a_id"
has_many :ctbls, foreign_key: "c_a_id"
end
class Btbl < ActiveRecord::Base
belongs_to :atbl, foreign_key: "b_a_id"
### ここに Ctbl との has_many を定義したい ###
end
class Ctbl < ActiveRecord::Base
belongs_to :atbl, foreign_key: "c_a_id"
end
# atbls
id name
1 A1
# btbls
id name b_a_id
2 B1 1
# ctbls
id name c_a_id
3 C1 1
Bテーブル => Cテーブルのhas_many
関連 をどう設定するか?
has_many :ctbls, through: :atbl
を使う
- BテーブルとCテーブルはお互いにAテーブルのIDを保持しているので、
:through
でAテーブルを経由すれば紐付く
class Btbl < ActiveRecord::Base
belongs_to :atbl, foreign_key: "b_a_id"
has_many :ctbls, through: :atbl # ★★★
end
[Ruby2.2.2][Rails4.2.1](beers|test_arel)> bdata = Btbl.find(2)
Btbl Load (0.2ms) SELECT `btbls`.* FROM `btbls` WHERE `btbls`.`id` = 2 LIMIT 1
+----+------+--------+
| id | name | b_a_id |
+----+------+--------+
| 2 | B1 | 1 |
+----+------+--------+
1 row in set
[Ruby2.2.2][Rails4.2.1](beers|test_arel)> bdata.ctbls
Ctbl Load (0.3ms) SELECT `ctbls`.* FROM `ctbls` INNER JOIN `atbls` ON `ctbls`.`c_a_id` = `atbls`.`id` WHERE `atbls`.`id` = 1
+----+------+--------+
| id | name | c_a_id |
+----+------+--------+
| 3 | C1 | 1 |
+----+------+--------+
1 row in set
しかし、 お互い同じ内容のカラムを保持しているのにわざわざ経由テーブルと INNER JOIN
するのは無駄
btbls.b_a_id
と ctbls.c_a_id
を直接結合したい
has_many :ctbls, primary_key: "b_a_id", foreign_key: "c_a_id"
を使う
-
has_many :紐付け先, primary_key: "自TBLの結合用カラム", foreign_key: "紐付け先TBLの結合用カラム
と書くと良い
class Btbl < ActiveRecord::Base
belongs_to :atbl, foreign_key: "b_a_id"
has_many :ctbls, primary_key: "b_a_id", foreign_key: "c_a_id" ## ★★★
end
[Ruby2.2.2][Rails4.2.1](beers|test_arel)> bdata = Btbl.find(2)
Btbl Load (0.2ms) SELECT `btbls`.* FROM `btbls` WHERE `btbls`.`id` = 2 LIMIT 1
+----+------+--------+
| id | name | b_a_id |
+----+------+--------+
| 2 | B1 | 1 |
+----+------+--------+
1 row in set
[Ruby2.2.2][Rails4.2.1](beers|test_arel)> bdata.ctbls
Ctbl Load (0.4ms) SELECT `ctbls`.* FROM `ctbls` WHERE `ctbls`.`c_a_id` = 1
+----+------+--------+
| id | name | c_a_id |
+----+------+--------+
| 3 | C1 | 1 |
+----+------+--------+
1 row in set
-
INNER JOIN
してないのでパフォーマンス的に:through
するよりも有利- ただし経由テーブルにデータが存在することがMUST、という場合には当然
:through
すべき
- ただし経由テーブルにデータが存在することがMUST、という場合には当然
:through
の使い方で疑問に思うことがあったので、調査メモとして残しとく
Author And Source
この問題について(:primary_keyと:foreign_keyを同時指定して、主キーではないけど共通なカラム同士で関連付けする), 我々は、より多くの情報をここで見つけました https://qiita.com/jpshadowapps/items/2354f3463c06c109993d著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .