題記:ABP框架對多租戶場景提供了很好的支持,內建了多租戶的處理機制,今天咱們來深刻解析一下這一特性。html
最近在基於ABP框架(ASP.NET Boilerplate)開發了一個SaaS。因此接下來可能會時不時分享一下ABP方面的文章。今天來介紹一下ABP對多租戶提供的支持特性。git
ASP.NET Boilerplate是一個用最佳實踐和流行技術開發現代WEB應用程序的新起點,它旨在成爲一個通用的WEB應用程序框架和項目模板。ASP.NET Boilerplate 基於DDD的經典分層架構思想,實現了衆多DDD的概念(但沒有實現全部DDD的概念)。ABP不只架構設計和代碼寫的好,文檔也很全面詳實(這是一個開發框架被技術選型的基礎)。github
尤爲國內的不少熱心朋友還整理了中文的資料和文檔,好比郭陽銘的系列文章(http://www.cnblogs.com/mienreal/p/4528470.html)和ABP框架中國小組的中文文檔(https://github.com/ABPFrameWorkGroup/AbpDocument2Chinese)。數據庫
一般SaaS都是須要多租戶支持的。維基百科對多租戶的解釋是:軟件多租戶是指一個軟件架構的實例軟件運行在一個服務器上,但存在多個租戶。租戶是一組共享一個公共的用戶訪問特定權限的軟件實例。多租戶架構,軟件應用程序旨在提供每一個租戶專用的實例包括數據、配置、用戶管理、租戶個體功能和非功能屬性。多租戶與多實例架構,獨立的軟件實例表明不一樣的租戶操做。服務器
多租戶通常涉及以下幾種場景:架構
另外,除了針對租戶的數據庫之外,可能還須要一個全局的數據庫(稱之爲主機數據庫)來保存全局範圍的配置數據。在單數據庫狀況下,主機數據可能就和租戶數據放在一塊兒(甚至同一個數據表中)。框架
上面提到的全部多租戶場景,在ABP均可以支持。只須要在啓動配置中啓用多租戶便可。性能
Configuration.MultiTenancy.IsEnabled = true;
固然,最多見的場景恐怕就是單部署-單數據庫,因此ABP中內置了處理TenantId的機制(經過接口IMustHaveTenant或IMayHaveTenant來實現)。實體實現了IMustHaveTenant接口,會包含一個不能爲空的TenantId屬性,即意味着其中的數據庫須要基於TenantId來進行隔離。實現了IMayHaveTenant接口,會包含一個能爲空的TenantId屬性,在TenantId爲空的時候表明數據屬於主機範圍的,不爲空的時候表示數據基於租戶來隔離。編碼
而ABP經過一個特殊封裝的IAbpSession來給使用者提供當前TenantId的獲取,若是是主機用戶登陸系統,那麼TenantId就是爲空的,不然就是登陸用戶所在租戶的Id。架構設計
ABP並不是只是簡單的給你的實體類添加一個TenantId屬性,而是經過識別IMustHaveTenant或IMayHaveTenant接口,使用數據過濾機制(根據底層所用ORM不一樣有不一樣的實現方式)自動在你讀取數據的時候,基於當前AbpSession中的TenantId來過濾數據。也就是說,你查詢讀取數據的時候,寫「where item.TenantId == AbpSession.TenantId」 這樣的代碼是毫無必要的。
須要注意的是,若是實體實現的是IMustHaveTenant接口,且AbpSession.TenantId爲null的時候(即主機用戶),獲取到的數據是全部租戶的,除非你本身顯式進行過濾。而在IMayHaveTenant狀況下,AbpSession.TenantId爲null獲取到的是主機用戶的數據。
在多租戶的情形下,寫入數據也經過攔截機制(好比重寫DbContext的SaveChanges方法),能夠自動爲你的實體設置TenantId屬性,無論你用的是IMustHaveTenant仍是IMayHaveTenant。雖然官方文檔是推薦在建立實體的時候,老是顯示設置TenantId的,尤爲在使用IMayHaveTenant的時候(這也是abp使用者惟一須要關係這個屬性的地方)。可是,就我我的的見解而言,利用框架的緣由就是爲了讓編碼簡單,因此我仍是傾向於建議你們不用顯式設置TenantId。
最後,ABP也提供一系列機制讓你在代碼中切換tenant(包括租戶與主機間的切換)。
關於多租戶的官方文檔(http://www.aspnetboilerplate.com/Pages/Documents/Multi-Tenancy)最後的內容也詳細講到了切換租戶的一些最佳實踐。