Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

EclipseLink/DesignDocs/Multi-Tenancy/TablePerTenant

This feature will be a continuation of the multitenant feature that currently offers a SINGLE_TABLE or VPD type, see Multitenant

Table per tenant

The goal of this feature is to allow multiple application tenants to have a their own individual table per tenant. Table per tenant entities will be allowed where shared tables are used within the same persistence unit.

Requirements

  1. Support configuration of table per tenant entity types using EclipseLink specific annotations and/or eclipselink-orm.xml with the XML overriding the annotation.
  2. Ensure all READ, INSERT, UPDATE, DELETE operations populate and limit their effect to the defined table per tenant
  3. Tenants will share the same server session (table per tenant identifier must be updated/set per entity manager)
    1. Id generation must be unique across all tenants
  4. Schema generation??? TBD

Metadata Configuration

This document will focus only on the TABLE_PER_TENANT multi-tenant type. The type will enable individual tenant table(s) usage at the entity level using a context property that must be provided by the user.

  • The TABLE_PER_TENANT states that the table(s) (Table and SecondaryTable) for the given entity are individual tenant tables based on the user.
  • A TABLE_PER_TENANT type is used in conjunction with a table per tenant property definition to identify the user.

Important notes

  • Multi-tenant metadata can only be applied at the root level of the inheritance hierarchy when using a SINGLE_TABLE or JOINED inheritance strategy. A log warning will be issued otherwise.
  • It is possible to specify multi-tenant metadata within a TABLE_PER_CLASS inheritance hierarchy.

Short example

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

tenant1.EMP

EMP_ID VERSION F_NAME L_NAME GENDER
1 1 John Doe M

tenant2.EMP

EMP_ID VERSION F_NAME L_NAME GENDER
2 3 Jane Doe F

The following new EclipseLink metadata will be added.

Annotation usage

The new type will be added to possible value list for the existing @Multitenant annotation. See Multinancy for more configuration documentations of this annotation.

This means we will simple extend the MultitenantTenant enum to include TABLE_PER_TENANT.

public enum MultitenantType {
    /**
     * Specifies that table(s) the entity maps to includes rows for multiple tenants. 
     * The tenant discriminator column(s) are used with application context values to
     * limit what a persistence context can access.
     */
    SINGLE_TABLE, 
 
    /**
     * Specifies that the DB will handle the tenant filtering on all SELECT,
     * UPDATE and DELETE queries. Using this type assumes that the platform
     * used with your persistence unit does indeed support VPD.
     */
    VPD
 
    /**
     * Specifies that different tables are used for each tenant. The table scan be uniquely
     * identified by name, schema/tablespace.
     */
    TABLE_PER_TENANT 
}

XML usage

The multitenant-type XML element will be expanded to include the new type.

<xsd:simpleType name="multitenant-type">
  <xsd:annotation>
    <xsd:documentation>
      ...
    </xsd:documentation>
  </xsd:annotation>
  <xsd:restriction base="xsd:token">
    <xsd:enumeration value="SINGLE_TABLE"/>
    <xsd:enumeration value="VPD"/>
    <xsd:enumeration value="TABLE_PER_TENANT"/>
  </xsd:restriction>
</xsd:simpleType>

Metadata Processing Warnings and Exceptions

  • When a foreign key relationship exists to a Table Per Tenant entity and exception will be raised. That is:
    • @ManyToOne
    • @OneToOne with no mappedBy
    • @ManyToMany with no mappedBy

The Table Per Tenant entity must always be the owner of the relationship (if any).

Property configuration and caching

At runtime the tenant per table property can be specified via a persistence unit definition, passed to a create entity manager factory call or set directly on the entity manager.

The order of precendence for tenant discriminator column properties is as follows:

  • EntityManager
  • EntityManagerFactory
  • Application context (when in a Java EE container)
<persistence-unit name="multi-tenant">
  ...
  <properties>
    <property name="eclipselink.table-per-tenant-id" value="gpelleti"/>
    ...
  </properties>
</persistence-unit>

Or alternatively (and most likely preferred) in code as follows:

HashMap properties = new HashMap();
properties.put(MULTITENANT_TABLE_PER_TENANT, gpelleti);
...     
EntityManager em = Persistence.createEntityManagerFactory("multi-tenant", properties).createEntityManager();
 
// OR set directly on the Entity Manager.
 
em.setProperty(PersistenceUnitProperties.MULTITENANT_TABLE_PER_TENANT, "gpelleti");

By default, tenants will share the EMF. If this is not the desired behavior it can be set through the following (exisintg property):

  • eclipselink.multitenant.tenants-share-emf

When set to false, users will need to provide a unique session name. Full caching is in effect at this point.

  • eclipselink.session-name

When the EMF is shared, by default, tenants will not share the cache, meaning table per tenant entities will have an ISOLATED setting. To allow these entities to share the cache, the following property can be set to true:

  • eclipselink.multitenant.tenants-share-cache

When the cache is shared, table per tenant entities will have a PROTECTED setting.

Swapping table per tenants during an active EntityManager is not allowed.

Core

A table per tenant policy will be set per individual entity.

The meat of the table per tenant strategy will be through database level settings and access provisions and the table per tenant property will directly correlated with EclipseLink's descriptor table qualifier (which is added to all tables relating to that descriptor, table and secondary table).

We will also expand this table qualifier setting to all mappings of the descriptor that use a relation table (Many to many and one to one). When those mappings are created, there is no notion of a table qualifier/schema at that point. Since the table per tenant entity is the owner of the relationship it is only fair to assume that its relation table must also have the same qualifier. It is entirely possible though (with unique id's across all tenants for table per tenant entities) to not have this restriction/assumption in place however.

Under the same assumption, element collection tables should also have the table per tenant identifier as well, but again not necessary when unique id's are employed across all tenants.

TBD, new flag to indicate if the tables are per tenant or not. This opens up caching issues though, in that, we could never use the level 2 cache and would always have to force the table per tenant entities to an isolated session?? Some unknowns here.

When the tenant per table identifier is set, a re-initialization of the query manager will be performed.

Core/Runtime Exceptions

  • When a table per tenant is not set, a database exception will be thrown (invalid table name etc.)

Properties

The table per tenant property (eclipselink.table-per-tenant-id) will be available from:

  • org.eclipse.persistence.config.EntityManagerProperties.MULTITENANT_TABLE_PER_TENANT
  • org.eclipse.persistence.config.PersistenceUnitProperties.MULTITENANT_TABLE_PER_TENANT

Java example

EntityManager em = createEntityManager(MULTI_TENANT_PU);
em.setProperty("eclipselink.table-per-tenant-id", "gpelleti");
em.setProperty(EntityManagerProperties.MULTITENANT_TABLE_PER_TENANT, "gpelleti");

Querying

Full querying should be available to the user through the following entity manager operations:

  • persist
  • find
  • refresh

And the following queries:

  • named queries
  • update all
  • delete all

NOTE: EclipseLink will not modify, therefore, support multi-tenancy through named native queries. When using these types of queries within a multi-tenant environment, the user will need to be aware and handle any multi-tenancy issues (schemas) themselves directly in their native query. To all intent and purpose, named native queries should be avoided in a multi-tenant environment.

DDL generation

DDL generation will not be supported?? Need a table per tenant for all tenants to generate a table for each, that plus permissions will need to be set (access provisions etc). TBD.

Open/Future items

Back to the top