@Multitenant

The @Multitenant annotation specifies that a given entity is shared among multiple tenants of an application. The multitenant type specifies how the data for these entities are to be stored on the database for each tenant. Multitenancy can be specified at the entity or mapped superclass level.

Annotation Elements

Table 2-32 describes this annotation's elements.

Table 2-32 @Multitenant Annotation Elements

Annotation Element Description Default

boolean includeCriteria

Indicates if the database requires the tenant criteria to be added to the SELECT, UPDATE, and DELETE queries.

true

MultitenantType value

Specifies the multitenant strategy to use: SINGLE_TABLE, TABLE_PER_TENANT, or VPD.

SINGLE_TABLE


Usage

To use the @Multitenant annotation, include the annotation with an @Entity or @MappedSuperclass annotation. For example:

@Entity
@Multitenant
...
public class Employee() {
  ...
}
 

Three types of multitenancy are available:

Example

Example 2-58 shows a simple example of a @Multitenant annotation. In this example, the Player entity has rows for multiple tenants stored in its default PLAYER table and that the default TENANT_ID column is used as a discriminator along with the default context property eclipselink.tenant-id.

Example 2-58 Minimal @Multitenant Annotation

@Entity
@Multitenant
public class Player  {
}

To have your application use a shared EntityManagerFactory and have the EntityManager be tenant specific, your runtime code might be:

Map<String, Object> emProperties = new HashMap<String, Object>();

emProperties.set("eclipselink.tenant-id", "HTHL");

EntityManager em = emf.createEntityManager(emProperties);

Review "Single-Table Multitenancy", "Table-Per-Tenanat Multitenancy", and "VPD Multitenancy" for more detailed examples.


Single-Table Multitenancy

The SINGLE_TABLE multitenant type specifies that any table to which an entity or mapped superclass maps can include rows for multiple tenants. Access to tenant-specific rows is restricted to the tenant.

Tenant-specific rows are associated with the tenant by using tenant discriminator columns. The discriminator columns are used with application context values to limit what a persistence context can access.

The results of queries on the mapped tables are limited to the tenant discriminator value(s) provided as property values. This applies to all insert, update, and delete operations on the table. When multitenant metadata is applied at the mapped superclass level, it is applied to all subentities unless they specify their own multitenant metadata.

Note:

In the context of single-table multitenancy, “single-table” means multiple tenants can share a single table, and each tenant's data is distinguished from other tenants' data via the discriminator column(s). It is possible to use multiple tables with single-table multitenancy; but in that case, an entity's persisted data is stored in multiple tables (Table and SecondaryTable), and multiple tenants can share all the tables.

For more information how to use tenant discriminator columns to configure single-table multitenancy, see "@TenantDiscriminatorColumn".

Examples

The following example uses @Multitenant, @TenantDiscriminatorColumn, and a context property to define single-table multitenancy on an entity:

Example 2-59 Example Using @Multitenant

@Entity 
@Table(name=“EMP”) 
@Multitenant(SINGLE_TABLE) 
@TenantDiscriminatorColumn(name = “TENANT_ID”, 
   contextProperty = "employee-tenant.id")

The following example uses the <multitenant> element to specify a minimal single-table multitenancy. SINGLE_TABLE is the default value and therefore does not have to be specified.

Example 2-60 Example Using <multitenant>

<entity class="model.Employee">
  <multitenant/>
  <table name="EMP"/>
  ...
</entity>

Table-Per-Tenanat Multitenancy

The TABLE_PER_TENANT multitenant type specifies that the table(s) (Table and SecondaryTable) for an entity are tenant-specific tables based on the tenant context.. Access to these tables is restricted to the specified tenant. Relationships within an entity that use a join or collection table are also assumed to exist within that context.

As with other multitenant types, table-per-tenant multitenancy can be specified at the entity or mapped superclass level. At the entity level, a tenant context property must be provided on each entity manager after a transaction has started.

Table-per-tenant entities can be mixed with other multitenant-type entities within the same persistence unit.

All read, insert, update, and delete operations for the tenant apply only to the tenant's table(s).

Tenants share the same server session by default. The table-per-tenant identifier must be set or updated for each entity manager. ID generation is assumed to be unique across all the tenants in a table-per-tenant strategy.

To configure table-per-tenant multitenancy, you must specify:

  • A table-per-tenant property to identify the user. This can be set per entity manager, or it can be set at the entity manager factory to isolate table-per-tenant per persistence unit.)

  • A tenant table discriminator to identify and isolate the tenant's tables from other tenants' tables. The discriminator types are SCHEMA, SUFFIX, and PREFIX. For more information about tenant discriminator types, see "@TenantTableDiscriminator".

Examples

The following example shows the @Multitenant annotation used to define table-per-tenant multitenancy on an entity. @TenantTableDiscriminator(SCHEMA) specifies that the discriminator table is identified by schema.

Example 2-61 Example Using @Multitenant with @TenantTableDiscriminator

@Entity
@Table(name=“EMP”)
@Multitenant(TABLE_PER_TENANT)
@TenantTableDiscriminator(SCHEMA)
public class Employee {
    ...
}

The following example shows the <multitenant> element and the <tenant-table-discriminator> elements used to define a minimal table-per-tenant multitenancy.

Example 2-62 Example Using <multitenant> with <tenant-table-discriminator>

<entity class="Employee">
  <multitenant type="TABLE_PER_TENANT">
    <tenant-table-discriminator type="SCHEMA"/>
  </multitenant>
  <table name="EMP">
  ...
</entity>

VPD Multitenancy

The VPD (Virtual Private Database) multitanancy type specifies that the database handles the tenant filtering on all SELECT, UPDATE and DELETE queries. To use this type, the platform used with the persistence unit must support VPD.

To use TopLink VPD multitenancy, you must first configure VPD in the database and then specify multitenancy on the entity or mapped superclass, using @Multitenant and @TenantDiscriminatorColumn:

Examples

Example 2-63 shows VPD multitenancy defined on an entity. As noted above, VPD in the database must also be configured to enable VPD multitenancy. In this case, the VPD database was configured to use the USER_ID column to restrict access to specified rows by specified clients. Therefore, USER_ID is also specified as the tenant discriminator column for the TopLink multitenant operations.

Example 2-63 Example Using @Multitenant(VPD)

The following example shows

@Entity
@Multitenant(VPD)
@TenantDiscriminatorColumn(name = "USER_ID", contextProperty = "tenant.id")
@Cacheable(false)
 
public class Task implements Serializable {
...
...

The following example shows...

Example 2-64 Example Using <multitenant>

<entity class="model.Employee"> 
  <multitenant type="VPD">
    <tenant-discriminator-column name="USER_ID" context-property="tenant.id"/> 
  </multitenant>
  <table name="EMPLOYEE"/>
  ...
</entity>

See Also