很多程序使用的數據庫都包含有多個表,而且通常一些表之間還有關聯關系,訂單常含有多個條目,而一個條目又關聯到一種商品,一個商品可能又屬於多個商品分類,一個商品分類裡又包含有多個不同的商品。
在數據庫中,這些關聯表現為使用主鍵值把表關聯起來,也就是外鍵,但是這屬於底層的范疇,我們需要處理Model對象間的關聯,而不是數據庫中的列和鍵。如果一個訂單含有多個條目,我們需要有辦法來維持,處理它們的關系,如果一個條目引用到一種商品,我們或許想這樣做:
price = line_item.product.price
而不願像下面這樣麻煩:
product_id = line_item.product_id product = Product.find(product_id) price = product.price
Active Record可以幫助我們,作為ORM的一部分,Active Record將低級別的數據庫中的外鍵轉換成高級別的對象間的映射。處理了三種基本情況:
A表中的一條記錄和B表的零條或一條記錄相關聯。
A表中的一條記錄和B表的任意多條記錄相關聯。
A表中的任意多條記錄和B表的任意多條記錄相關聯。
下面我們來看看怎樣創建外鍵(Foreign Key),我們使用下面的DDL來創建表,它們之間指定了關聯:
create table products ( id int not null auto_increment, title varchar(100) not null, /* . . . */ primary key (id) ); create table orders ( id int not null auto_increment, name varchar(100) not null, /* ... */ primary key (id) ); create table line_items ( id int not null auto_increment, product_id int not null, order_id int not null, quantity int not null default 0, unit_price float(10,2) not null, constraint fk_items_product foreign key (product_id) references products(id), constraint fk_items_order foreign key (order_id) references orders(id), primary key (id) );
在上面的DDL中,訂單和條目關聯,條目又關聯到具體的商品。注意這裡的命名約定,外鍵的名字product_id,product是products表的單數形式,然後再加上表的主鍵名字_id構成外鍵名。
上面的DDL中,訂單和條目是一對多的關系,還有一種是多對多關系,例如,一種商品屬於多個商品分類,一個商品分類又含有多種商品。對這種情況,通常我們使用第三個表,叫做結合表,這個表只包含兩個要關聯的表的id:
create table products ( id int not null auto_increment, title varchar(100) not null, /* . . . */ primary key (id) ); create table categories ( id int not null auto_increment, name varchar(100) not null, /* ... */ primary key (id) ); create table categories_products ( product_id int not null, category_id int not null, constraint fk_cp_product foreign key (product_id) references products(id), constraint fk_cp_category foreign key (category_id) references categories(id) );
注意結合表的命名,在這裡Rails的約定為兩個表名,中間用下劃線分開,表名按照字母排序,Rails會自動找到categories_products表將categories表和products鏈接起來,如果你沒有按照約定,那麼就要自己聲明,以便Rails能夠找到它。