在构建SaaS应用程序时,多租户架构的设计至关重要,它是用户与网站交互的第一道逻辑关卡。
引言
多租户数据库的设计通常有三种主流方法:
- 单一数据库模式:在这种模式下,每条数据都会标记一个租户ID,以此来识别数据归属。
- 独立数据库模式:每个租户拥有自己的数据库,实现了数据的完全隔离。
- 混合模式:基础数据存放于同一表中,而业务数据则分散存储在不同的数据库中。
无论采用哪种设计,识别租户身份以查询数据库是基本要求。
识别租户的方式多样:
- 通过不同的域名或子域名来识别租户,适用于所有场景(需要域名和DNS服务)。
- 通过用户ID获取租户信息,并存储在前端的cookie或header中,适用于单一数据库和混合模式,因为需要将不同租户的用户信息存储在同一表中以便查询。
以下示例展示了一个简单的实现,没有深入业务场景,功能如下:
- 用户通过不同的域名访问系统;
- 后台接收HTTP传入的域名并进行解析;
- 查询租户数据库,返回租户名称以供显示。
项目结构
创建解决方案,并在其下新增三个项目:
- try_MultiTenantApi:WebAPI项目,作为启动项目,租户的Service和IService也包含在此项目中,实际应用时应分离到业务层。
- MultiTenantApi.Models:类库项目,存储租户对象。
- MultiTenantApi.Data:数据层,使用EF Core,包含DbContext和迁移文件。
实体定义
在MultiTenantApi.Models
中新增实体Tenant
:
public class Tenant
{
public int Id { get; set; }
public string Identifier { get; set; } // 租户标识符,例如域名
public string Name { get; set; }
public string ConnectionString { get; set; } // 每个租户的独立数据库连接字符串
}
数据层配置
在MultiTenantApi.Data
中引入NuGet包,确保与项目.NET版本一致。
这些包的功能如下:
- Microsoft.EntityFrameworkCore:Entity Framework Core是一个现代的对象-关系映射器(ORM),支持LINQ查询、变更跟踪、更新和模式迁移。
- Microsoft.EntityFrameworkCore.Design:提供Entity Framework Core工具的共享设计时组件,包括创建和管理迁移的工具。
- Microsoft.EntityFrameworkCore.Proxies:为Entity Framework Core提供延迟加载代理,减少内存使用,提高性能。
- Microsoft.EntityFrameworkCore.SqlServer:提供针对Microsoft SQL Server的数据库提供程序。
- Microsoft.EntityFrameworkCore.Tools:提供Entity Framework Core工具,用于Visual Studio的NuGet Package Manager Console。
数据上下文
新增数据上下文:
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions options)
: base(options)
{
}
public DbSet Tenants { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity().HasData(
new Tenant { Id = 1, Identifier = "tenant1", Name = "Tenant 1", ConnectionString = "Server=(localdb)\\mssqllocaldb;Database=TenantDb1;Trusted_Connection=True;" },
new Tenant { Id = 2, Identifier = "tenant2", Name = "Tenant 2", ConnectionString = "Server=(localdb)\\mssqllocaldb;Database=TenantDb2;Trusted_Connection=True;" }
);
}
}
请注意,实际应用中需要根据具体情况调整数据库连接字符串。
服务层
在try_MultiTenantApi
中引入NuGet包,并新建类TenantService
:
public interface ITenantService
{
Task GetTenantByIdentifierAsync(string identifier);
}
public class TenantService : ITenantService
{
private readonly ApplicationDbContext _context;
public TenantService(ApplicationDbContext context)
{
_context = context;
}
public async Task GetTenantByIdentifierAsync(string identifier)
{
return await _context.Tenants.FirstOrDefaultAsync(t => t.Identifier == identifier);
}
}
相关文章
暂无评论...