

新闻资讯
技术学院EF Core 多租户无内置支持,需按场景权衡:Database-per-Tenant(物理隔离、高安全)、Schema-per-Tenant(逻辑隔离、易维护)、Row-level Filtering(轻量但需严格审查),核心是租户上下文早于 DbContext 创建并贯穿请求链路。
EF Core 本身不内置多租户支持,但可以通过多种方式实现数据隔离,核心在于请求上下文感知 + 查询拦截 + 模型配置。关键不是“选哪种方案”,而是根据租户规模、隔离强度、运维成本和现有架构来权衡。
每个租户独占一个数据库,物理级隔离,安全性最高,扩展性好,适合 SaaS 中大型客户或合规要求严的场景。
IDbContextFactory 或自定义 DbContext 构造时传入租户 ID,拼接出对应连接字符串dotnet ef migrations script + 脚本分发,或运行时调用 MigrateAsync())所有租户共享同一数据库,但各自拥有独立 Schema(如 PostgreSQL/SQL Server),逻辑隔离,兼顾安全与维护效率。
OnModelCreating 中通过 entity.ToTable("Users", tenantSchemaName) 统一指定 SchemaITenantContext)CREATE SCHEMA;PostgreSQL 自动支持)DefaultSchema 是全局设置,无法 per-context 覆盖,必须显式调用 ToTable(..., schema)
所有租户数据混存在同一张表,靠查询自动附加 TenantId == current 条件,开发最轻量,但依赖严格审查,适合内部系统或租户间无强隔离需求的场景。
modelBuilder.Entity().HasQueryFilter(x => x.TenantId == _tenantService.GetCurrentTenantId())
_tenantService 必须是 Scoped 生命周期,且在 Filter 中不能直接注入(EF Core 不支持),应改用 DbContext 构造函数传入或通过 IServiceProvider 解析(推荐前者)
器:context.Set().IgnoreQueryFilters()
TenantId 字段建立复合索引(如 (TenantId, CreatedAt)),避免全表扫描无论采用哪种隔离方式,租户识别必须早于 DbContext 创建,且线程/请求安全。
tenant_id、子域名(acme.example.com)、请求头(X-Tenant-ID)、API Key 查表AddScoped() 注入,并在中间件中解析并填充租户信息ITenantContext 或其关键值(如 string TenantId),避免在 OnConfiguring 中延迟解析基本上就这些。没有银弹,Database-per-Tenant 最稳,Row-level 最省事,Schema-per-Tenant 是平衡之选。实际项目中常混合使用(比如核心租户表用 DB 隔离,日志类表用行过滤)。关键是把租户上下文流透整个请求链路,别让它在 DbContext 这里断掉。