多租户解析与Demo

在构建SaaS应用程序时,多租户架构的设计至关重要,它是用户与网站交互的第一道逻辑关卡。

引言

多租户数据库的设计通常有三种主流方法:

  1. 单一数据库模式:在这种模式下,每条数据都会标记一个租户ID,以此来识别数据归属。
  2. 独立数据库模式:每个租户拥有自己的数据库,实现了数据的完全隔离。
  3. 混合模式:基础数据存放于同一表中,而业务数据则分散存储在不同的数据库中。

无论采用哪种设计,识别租户身份以查询数据库是基本要求。

识别租户的方式多样:

  1. 通过不同的域名或子域名来识别租户,适用于所有场景(需要域名和DNS服务)。
  2. 通过用户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版本一致。

引入NuGet包

这些包的功能如下:

  1. Microsoft.EntityFrameworkCore:Entity Framework Core是一个现代的对象-关系映射器(ORM),支持LINQ查询、变更跟踪、更新和模式迁移。
  2. Microsoft.EntityFrameworkCore.Design:提供Entity Framework Core工具的共享设计时组件,包括创建和管理迁移的工具。
  3. Microsoft.EntityFrameworkCore.Proxies:为Entity Framework Core提供延迟加载代理,减少内存使用,提高性能。
  4. Microsoft.EntityFrameworkCore.SqlServer:提供针对Microsoft SQL Server的数据库提供程序。
  5. 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);
    }
}
版权声明:程序员胖胖胖虎阿 发表于 2024年12月24日 下午2:54。
转载请注明:多租户解析与Demo | 胖虎的工具箱-编程导航

相关文章

暂无评论

暂无评论...