Class TenantAwareEntity

java.lang.Object
io.leandev.appfuse.jpa.tenant.TenantAwareEntity
All Implemented Interfaces:
TenantAware

@MappedSuperclass public abstract class TenantAwareEntity extends Object implements TenantAware

租戶感知實體基類

所有需要多租戶數據隔離的 Entity 都應繼承此類(或其子類)。租戶隔離由 Hibernate 原生 discriminator 多租戶TenantId)承擔,見 ADR-016

  • Session 建構時TenantContextIdentifierResolver 決定租戶, Hibernate 自動套用租戶 filter——不需任何人呼叫 enableFilter
  • filter 的 applyToLoadByKey = true,故 entityManager.find() 亦受過濾(不需手寫租戶比對
  • INSERT 時TenantIdGeneration 注入租戶;已顯式設值者:root 放行、非 root 須相符 (不符拋 PropertyValueException
  • updatable = false:租戶歸屬不可被 UPDATE 改寫

使用方式

方式 1:直接繼承(不需要審計功能)

@Entity
@Table(name = "products")
public class Product extends TenantAwareEntity {
    // ...
}

方式 2:建立應用層基類加入審計功能(推薦)

@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class AuditableTenantEntity extends TenantAwareEntity {

    @CreatedBy
    @Column(name = "created_by", updatable = false)
    private String createdBy;

    @CreatedDate
    @Column(name = "created_date", updatable = false)
    private Instant createdDate;

    @LastModifiedBy
    @Column(name = "last_modified_by")
    private String lastModifiedBy;

    @LastModifiedDate
    @Column(name = "last_modified_date")
    private Instant lastModifiedDate;
}

設計說明

  • tenantId 使用 String 欄位而非 @ManyToOne 關聯,避免不必要的 JOIN 查詢(ADR-001 的欄位策略,維持不變)
  • 建立前必須指明租戶TenantContext.runAs(tenantId, ...)(首選)或顯式 setTenantId(...); 兩者皆無時由 @PrePersist 守衛擋下(見 rejectRootTenantOnPersist()
  • 先設 TenantContext、再開交易——租戶綁在 Session 建構時
  • 不包含審計欄位,讓應用層自行決定是否需要審計功能
  • 不包含 @Id 欄位,讓子類自行定義主鍵策略
See Also:
  • Constructor Details

    • TenantAwareEntity

      public TenantAwareEntity()
  • Method Details

    • getTenantId

      public String getTenantId()
      Description copied from interface: TenantAware
      取得此 Entity 所屬的租戶 ID
      Specified by:
      getTenantId in interface TenantAware
      Returns:
      租戶 ID
    • setTenantId

      public void setTenantId(String tenantId)
      Description copied from interface: TenantAware

      設定此 Entity 所屬的租戶 ID

      一般情況由 Hibernate @TenantId 於寫入時自動注入,不需手動呼叫;root session 要替特定租戶建立資料時才顯式設定(見 TenantAwareEntity 的守衛說明)。

      Specified by:
      setTenantId in interface TenantAware
      Parameters:
      tenantId - 租戶 ID