Datomic/Datascript入门:多Schema使用及关联字段定义最佳实践
问题解答
1. 是否只需要一个数据库?
是,该场景完全可以仅使用一个Datomic/Datascript数据库,两类数据属于同一业务域的关联数据,拆分多个数据库反而会增加跨库关联查询的额外成本,完全没有必要。
2. 如何区分两套不同业务的Schema?
你当前的做法已经符合最佳实践:通过属性的命名空间天然隔离不同业务域的定义。:country/前缀的属性归属于国家基础信息域,:sales/前缀的属性归属于销售数据域,Datomic/Datascript的Schema以单个属性为核心组织,带不同命名空间的属性不会产生任何冲突,不需要额外做隔离处理。
3. Schema和数据的提交顺序
- Schema定义建议先全量提交完成后再插入业务数据:虽然Datascript支持无Schema插入,但提前提交所有属性的定义可以开启数据库层面的类型、唯一性等校验,避免脏数据写入。
- 业务数据的提交顺序分两种情况:
- 如果你用字符串存国家编码做软关联:国家数据和销售数据的提交没有强制先后顺序
- 如果你用下文提到的实体引用做关联:需要先提交国家基础数据,再提交销售数据
4. Schema是分两套还是统一一套?
你贴的统一Schema写法是完全合规的。Datomic/Datascript的Schema本身就是全库属性的统一集合,不需要物理拆分。
如果业务逻辑复杂、属性数量多,为了代码维护方便,也可以按业务域拆成多个Schema变量再合并提交,示例如下:
;; 国家域Schema (def country-schema {:country/code {:db/valueType :db.type/string :db/unique :db.unique/identity} :country/name {:db/valueType :db.type/string}}) ;; 销售域Schema (def sales-schema {:sales/account {:db/valueType :db.type/string :db/unique :db.unique/identity} :sales/country {:db/valueType :db.type/ref} :sales/amount {:db/valueType :db.type/integer}}) ;; 合并为全库Schema提交 (def schema (merge country-schema sales-schema))
5. 如何声明两个属性的关联关系?
你当前用字符串存国家编码的方式属于软关联,Schema层面没有内置的声明方式,只能在业务层自行校验关联一致性。
更推荐使用Datomic/Datascript原生的**实体引用类型(:db.type/ref)**实现关联,不需要额外定义sales/country-code字段,直接将sales/country定义为ref类型指向国家实体即可,优势是:
- 数据库层面自动保证引用的国家实体真实存在,避免code拼写不一致的脏数据
- 查询时不需要写等值连接,直接通过属性路径即可关联查询
实体引用方式的使用示例
插入销售数据时直接用lookup ref关联国家:
(d/transact! conn [{:sales/country [:country/code "CN"] :sales/amount 1000 :sales/account "XYZ"} {:sales/country [:country/code "CN"] :sales/amount 1000 :sales/account "AAA"} {:sales/country [:country/code "BR"] :sales/amount 1000 :sales/account "BBB"}])
查询中国所有销售记录的语句:
(d/q '[:find [?sales ...] :in $ ?country-name :where [?c :country/name ?country-name] [?sales :sales/country ?c]] (d/db conn) "China")
内容的提问来源于stack exchange,提问作者alex314159
相关产品推荐
相关产品推荐

