题记: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)最后的内容也详细讲到了切换租户的一些最佳实践。