不知道大家有沒有跟我一樣,曾經為了該如何設計 SQL 資料表的主鍵 (primary key) 而困擾不已?
每次遇到這種問題,第一個要考慮的就是:
如果說決定了要使用代理鍵,接下來的問題就是,該怎麼決定代理鍵的資料型態:
然後,又要考慮會不會有列舉攻擊 (enumeration attacks)、效能夠不夠好?到底是要使用可迴避列舉攻擊的整數、還是要選擇有加強效能的 UUID ?
在 Datomic 的世界,主鍵就是資料實體編碼 (entity id),就是這麼簡單。
有一個簡單的預設選項對我來講這是一大解脫。這有點像是從 C++ 語言改成寫 Java 之後,就再也不用去想記憶體的 new/delete 。從 JavaScript 改寫 Clojure 之後,所有的容器類別都是 persistent collection,就再也不用去想什麼時候需要 deepClone() 、什麼時候不需要了。做應用軟體開發,光是要想清楚業務規則就已經夠累人了,如果使用的工具還動不動提供五、六種效能與安全性的設計排列組合,真的是會嚴重的決策疲勞,讓人很想要隨便亂選一個。
由於 Datomic 讓每一個資料實體,都有同一型態的資料實體編碼,所以這也可以推導出一些對應的最佳實踐。
註:條件限制參考 Day26
:db/ident
Day 24 我們有列出,在 Datomic 資料庫裡,屬性可以使用的資料型別。在眾多可以使用的資料型別中,相對於傳統的 SQL 資料庫,缺少了列舉類型 (enum type)。
然而,其實 Datomic 對於列舉類型的作法有獨特的最佳實踐。該最佳實踐由主要有三點構成:
:db/ident
來定義列舉類型,列舉類型本身會是資料實體 (entity)。:db.type/ref
。[
;; 定義列舉類型 :country/CA
{:db/ident :country/CA}
;; 定義列舉類型 :country/JP
{:db/ident :country/JP}
;; 定義屬性 :artist/country
;; 並且讓這個屬性可以指向某個列舉類型的資料實體
{:db/ident :artist/country
:db/valueType :db.type/ref
:db/cardinality :db.cardinality/one
:db/doc "An artist's country of residence"}
]
[{:artist/name "Leonard Cohen"
:artist/country :country/CA}]
在寫入真實資料的時候,:artist/country
由於是 :db.type/ref
的資料型態,所以它右邊對應的值應該要是資料實體編碼 (entity id)。然而,上述的程式碼是正確的,因為在 Datomic ,凡是用 :db/ident
定義的列舉類型,都可以自動轉換成它的資料實體編碼。