浴室沉思 聊聊ORM

2022-04-05 11:21:56 字數 2223 閱讀 9574

平時在乙個ef群摸魚,日常問題可以歸納為以下幾種:

這條sql用linq怎麼寫?

ef可以呼叫我寫的儲存過程麼?

ef好慢啊一些複雜查詢寫起來好麻煩……

orm是隨著物件導向(oop)而來的。很早的時候rdb一統天下,大家也習慣了面向資料的開發習慣(其實現在也是)。oop出來後業界就發現了問題:rdb是基於數學理論的,而物件導向(oop)是從軟體工程的基本原則發展出來的,兩套理論存在著阻抗,例如現在我們定義乙個簡單的部落格物件:

public class blog

public string title

public string content

public listtags

}

在這個部落格物件中有個字串泛型集合的標籤屬性,如果要持久化在rdb中一般用兩種方法:1、標籤單獨一張表,blog表與tag表一對多關係;2、直接將tags序列化(新一代的rdb提供的json功能,所以一般是json序列化)儲存到blog表中,用ddd的概念來說就是一種值物件(value object)。

我們可以看到,第一種做法如果是直接將表對映到entity,那麼我們最終得到的blog型別可能並不是根據業務設計出來的樣子,也就是說業務物件為rdb持久化的技術而妥協設計了。第二種方法看起來不錯,但已經屬於newsql的範疇,和rdb無關。

擴充套件閱讀:阻抗失配不僅僅是上述問題那麼簡單,例如oop三要素——封裝、繼承、多型,假如你的業務物件存在繼關係,那麼在rdb中該如何描述?ef中提供了tph (table per hierarchy,父子類在同一張表,ef自動新增discriminator欄位用於標識屬於哪一型別)、tpt (table per type,父子類在不同的表,子類表只包含子類屬性,通過相同的id來關聯父類表上相同的entity父類資料)以及tpc(table per concrete type,沒用過,也沒見人用過,父子類在不同的表,父類的屬性在子類表中也會存在,估計是為了優化query)三種方式,大家可以找下資料,在這裡不做展開。

正確地使用orm第乙個前提是,專案必須是oop設計,解析業務後先進行業務物件的建模,然後再通過orm持久化業務物件的狀態。以ef為例,基本排除了db first以及model first的做法,因為後兩者屬於面向資料庫設計,所以ef core只保留code first除了更為精簡外,其實也更符合orm的實踐。

然而:

這沒有解決搜尋(query)問題啊。

在這裡我們要了解另乙個概念——cqs(命令查詢分離)。

cqs最早提出於2023年bertrand meyer的《物件導向軟體架構》,可以歸納為「原則上乙個方法不應該對資料造成影響(增刪改)的同時又返回資料」。以是否對資料造成影響我們可以將操作分成兩類:

查詢(query):返回資料,不修改資料,不會產生***。

命令(command):修改資料,不返回資料,遵守單一職責原則。

在具體落地的專案中,查詢往往千變萬化,複雜的查詢甚至要多表鏈結(大於3)還要進行聚合處理。其實我們可以看到,這裡的查詢幾乎可以當作是弱報表——而幾乎所有的這些查詢,都不是oop的功能。

因此雖然可以實現複雜查詢,但orm並不適用於cqs中的查詢(query)端。更好的做法是將專案的功能分成命令和查詢兩塊,然後只在命令端使用orm,query端怎麼快怎麼來——當然具體實現也可以兩邊都用ef,但c端要當作orm用,q端直接執行sql語句。

擴充套件閱讀:cqs並不是死規矩,例如stack的pop操作,有返回結果的同時也會改變stack本身。cqs落實到實際專案中並不是真的將操作簡單地分成兩類,比較簡單的分法是:頁面展示的一般是q端。一些專業的專案c端甚至可以只通過id來獲取業務物件,這有助於倉儲層的服務化以及事件溯源(event sourcing)的實現,以及在分布式系統中處理冪等。

最終總結,正確的使用orm並沒有想象中那麼簡單也沒有那麼難,其實也就是兩條經驗之談:

1、必須是oop設計,先使用code first建好業務模型後再考慮如何持久化。

到了最後聊聊一些題外話,現在已經有各種ddd框架,但用了ddd框架並不代表你的專案就是ddd。同時有些ddd框架的實現就有待商榷,例如abp其倉儲層的設計就存在問題,因為它持久化的並不是do(domain object)的狀態而是po,這導致abp的專案更類似於ddd lite,這個問題我們以後有時間再說。

關於ORM的浴室沉思

平時在乙個ef群摸魚,日常問題可以歸納為以下幾種 這條sql用linq怎麼寫?ef可以呼叫我寫的儲存過程麼?ef好慢啊一些複雜查詢寫起來好麻煩 orm是隨著物件導向 oop 而來的。很早的時候rdb一統天下,大家也習慣了面向資料的開發習慣 其實現在也是 oop出來後業界就發現了問題 rdb是基於數學...

足球沉思錄

本部落格用於記錄我平時踢球的反思和總結。也許聽起來有點怪異 只聽過寫學習總結或工作總結的,你踢個球還寫什麼總結?踢球不就圖個開心嗎?我以前的想法也是這樣,只把踢球當做鍛鍊身體 放鬆身心的一種活動,踢得開心就行了,而不太在意自己踢得怎樣 存在什麼問題和怎麼改進等等。直到上個月有次週三晚上踢球,我被換到...

python iocp 聊聊IOCP,聊聊非同步程式設計

前言 io完成埠 io completion ports 在多核計算機的並行非同步io請求方面提供了一種高效的執行緒模型。當程序建立乙個io完成埠時,系統建立乙個相關聯的佇列,其唯一目的是服務與那些請求。io完成埠通常和預先分配的執行緒池配合,相比於乙個乙個建立執行緒,這使其更快更高效。iocp在程...