AdoS0TenantQuery.cs 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243
  1. using SqlSugar;
  2. namespace Admin.NET.Plugin.AiDOP.Infrastructure;
  3. /// <summary>
  4. /// S0 租户内数据访问统一入口(S0-P0-TENANT-ID-CLOSURE)。
  5. ///
  6. /// 铁律:
  7. /// - tenant_id 是唯一租户安全边界;Domain / DomainCode / CompanyRefId / FactoryRefId
  8. /// 只能作为业务筛选条件,永远不得替代租户条件;
  9. /// - 租户值只来自 <see cref="AdoS0TenantScope.TryResolveRequired"/>(认证后的 JWT claim),
  10. /// 不接受前端 payload / query / DTO 传入;
  11. /// - 全局 AOP <c>ITenantIdFilter</c> 只作为 defense-in-depth,Controller 必须显式带租户条件;
  12. /// - 按主键取单条时,"不存在" 与 "属于其他租户" 一律返回 null,不泄露记录存在性。
  13. ///
  14. /// qms_* 系列实体未实现 ITenantIdFilter(全局 AOP 对其不生效),故另提供按物理列
  15. /// <c>tenant_id</c> 收口的重载,供 S0 Quality 控制器使用。
  16. /// </summary>
  17. public static class AdoS0TenantQuery
  18. {
  19. /// <summary>租户内查询(实现 ITenantIdFilter 的实体)。后续可继续追加业务筛选条件。</summary>
  20. public static ISugarQueryable<T> ScopedTo<T>(this SqlSugarRepository<T> rep, long tenantId)
  21. where T : class, ITenantIdFilter, new()
  22. => rep.AsQueryable().Where(x => x.TenantId == tenantId);
  23. /// <summary>租户内按主键取单条;不存在或不属当前租户均返回 null。</summary>
  24. public static Task<T> ByIdScopedAsync<T>(this SqlSugarRepository<T> rep, long id, long tenantId)
  25. where T : class, ITenantIdFilter, new()
  26. => rep.AsQueryable().Where(x => x.TenantId == tenantId).In(id).FirstAsync();
  27. /// <summary>
  28. /// 租户内查询(未实现 ITenantIdFilter、但物理表有 tenant_id 列的实体,如 qms_*)。
  29. /// 显式按物理列收口,不依赖全局 AOP。
  30. /// </summary>
  31. public static ISugarQueryable<T> ScopedToByColumn<T>(this SqlSugarRepository<T> rep, long tenantId)
  32. where T : class, new()
  33. => rep.AsQueryable().Where("tenant_id = @__tid", new { __tid = tenantId });
  34. /// <summary>租户内按主键取单条(qms_* 等无 ITenantIdFilter 实体);越租户一律返回 null。</summary>
  35. public static Task<T> ByIdScopedByColumnAsync<T>(this SqlSugarRepository<T> rep, long id, long tenantId)
  36. where T : class, new()
  37. => rep.AsQueryable().Where("tenant_id = @__tid", new { __tid = tenantId }).In(id).FirstAsync();
  38. }