iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 7
1
自我挑戰組

Laravel 實戰經驗分享系列 第 7

Laravel 實戰經驗分享 - Day7 初探 Laravel - 如何規劃資料庫關聯

鐵人賽第一周過了,想不到自己活下來了...
在這幾天一直處於拖延狀態,大概晚上七八點才開始寫 XD,不過還好前一天都先想好大概要寫甚麼內容了,因此還算上手,昨天講了 Laravel 的 Migration 功能,那麼就不得不提到一點關聯式資料庫的概念,雖然現在 NoSQL 相當流行,但是與一般的 RDBMS 應用範圍本來就沒辦法相提並論,以一般的網站架設,若需要定義好資料規格,或是應用中有交易功能的系統,都還是建議使用關聯式資料庫。
不過資料庫範圍實在是太大太廣,我這邊只能沾個醬油帶過,有錯誤也請指證,我會非常感謝您的 QQ。

資料的幾種關係

會需要關聯式的資料表,是因為某些資料可能會頻繁出現,因此我們會透過資料的關聯,以減少重複新建資料的狀況發生。通常資料表內會儲存主鍵以及外鍵描述資料的獨一性以及關聯性。

  • 主鍵 (primary key)
    一個資料表的只能有一個主鍵,因此可以利用它拿來識別該筆資料,以下面 users 的表來說,id 就是這個資料的主鍵,因為在整張資料表中,它是唯一的值,也能夠代表那筆資料。
  • 外鍵 (foreign key)
    其他資料表的主鍵,以建立彼此的關聯。以下面這張 transactions 來說,userId、orderId 都是屬於這張表的外鍵,可以透過這個外鍵來查詢其他的關聯資料表。

Entity Relation Diagram (實體關聯模型)

在設計資料庫前,需要先了解資料與資料間的關係,以便我們後續寫 Migration 建資料庫,資料間的關聯大致上分成三種,而 ERD 就是用來描述這些實體之間關係的工具。
以下的例子我用一個簡單的購物網站作為例子。
關於 Laravel 如何建立外鍵以及關聯等,可以參考官方文件

一對一

這個關係最好理解,指的就是這兩個實體的關係是一對一(廢話)。舉例來說,有時候因為隱私的關係,我們會另外將使用者的帳戶資料另外獨立一張表,因此消費者只會對應一個帳號,而一個帳號也只會有一個消費者。

實際狀況大概長這樣

Laravel Migration Code (節錄 up 函式)

  • users
public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->increments('id');
            $table->string('firstName', 45);
            $table->string('lastName', 45);
            $table->string('mobile', 45);
            $table->string('email', 45);
            $table->date('lastLogin');
            $table->unsignedInteger('user_account_id');
            $table->index(["user_account_id"], 'fk_users_user_account_idx');
            $table->foreign('user_account_id', 'fk_users_user_account_idx')
                ->references('id')->on('user_account')
                ->onDelete('no action')
                ->onUpdate('no action');
        });
    }
  • users_account
    public function up()
    {
        Schema::create('users_account', function (Blueprint $table) {
            $table->increments('id');
            $table->string('account', 45);
            $table->string('password', 45);
        });
    }

一對多

一對多所指的實體關係就會是一個物件的實體會對應多個實體,舉例來說,一個消費者可能會有多張信用卡,因此它所對應的關係就會是一對多,但是每一張信用卡仍然只能有一個使用者。你可能會覺得很奇怪,那一個消費者只有一張信用卡呢,算是一對一吧?
沒錯,其實一對多的關係本身就包含了一對一,只是描述他們的關係更精確來說是「不只一對一」的關係。

實際狀況大概長這樣

Laravel Migration Code

  • creditcard
    public function up()
    {
        Schema::create('creditcard', function (Blueprint $table) {
            $table->increments('id');
            $table->string('number', 45);
            $table->date('expiredDate');
            $table->integer('CVC');
            $table->unsignedInteger('users_id');
            $table->index(["users_id"], 'fk_creditcard_users1_idx');
            $table->foreign('users_id', 'fk_creditcard_users1_idx')
                ->references('id')->on('users')
                ->onDelete('no action')
                ->onUpdate('no action');
        });
    }

多對多

多對多的關係就更為複雜了點,我們舉商品以及標籤為例子,一個商品可以被貼上多個標籤,而每個標籤也可以涵蓋多種商品,因此這樣的關係就是多對多,並且在兩資料表間會再加上一張資料表以對應兩個實體的關係。

實際狀況(怕太亂就不另外做標註)

Laravel Migration Code

  • products
    public function up()
    {
        Schema::create('products', function (Blueprint $table) {
            $table->increments('id');
            $table->string('title');
            $table->integer('quantity');
            $table->decimal('price');
        });
    }
  • tags
    public function up()
    {
        Schema::create('tags', function (Blueprint $table) {
            $table->increments('id');
            $table->string('title'));
            $table->string('content');
        });
    }
  • products_tags
    public function up()
    {
        Schema::create('products_tags' function (Blueprint $table) {
            $table->increments('product_id');
            $table->unsignedInteger('tag_id');
            $table->index(["tag_id"], 'fk_product_has_tag_tag1_idx');
            $table->index(["product_id"], 'fk_product_has_tag_product1_idx');
            $table->foreign('product_id', 'fk_product_has_tag_product1_idx')
                ->references('id')->on('product')
                ->onDelete('no action')
                ->onUpdate('no action');
            $table->foreign('tag_id', 'fk_product_has_tag_tag1_idx')
                ->references('id')->on('tag')
                ->onDelete('no action')
                ->onUpdate('no action');
        });
    }

規劃資料庫的經驗談

現在有許多適合畫 ERD 的工具,我自己是習慣使用 MySQL Workbench 這套工具,使用上方便,滿符合 PHP 開發者的習慣,推薦給大家。通常我在了解要系統的整體需求後,即會依照他們的需求繪製 ERD,有助於了解目前整體的資料關聯以及架構,也讓你能夠因應需求做出符合客戶需求的系統。
老實講,我還是一個很菜的新人,規劃稍微有點規模的系統時,常會卡在實體之間的關聯性要怎麼定義,這部分比較吃實務經驗,所幸我在工作上有強大的前輩願意分享知識,也讓我對於規劃資料庫有初步的認識,今天這篇花了不少時間寫,但應該都是比較淺一點的經驗,可能有些觀念沒辦法解釋得很清楚,請大家見諒,有錯也麻煩告知!
明天見囉!


上一篇
Laravel 實戰經驗分享 - Day6 初探 Laravel - Migration
下一篇
Laravel 實戰經驗分享 - Day8 初探 Laravel - Route 路由設定
系列文
Laravel 實戰經驗分享30

尚未有邦友留言

立即登入留言