Support for discriminator-based multi-tenancy

Description

Follow up on HHH-5697 to add support for discriminator based set ups.

Considerations:

  1. What is the design of this in the metadata?

    1. At minimum we need to know the column to use for discrimination.

    2. Personally believe this should not be a attribute/property based. Should just name a column to use.

  2. We really should discover up front whether a SessionFactory contains any tenant data and require tenant identifier to be set in these cases.

    1. Explicit. The user passes us something saying that the SessionFactory involves multi tenancy

    2. Implied. Checking the connection provider (based on current split there) can indicate schema-based multi-tenancy. Checking all entities can imply the same for discriminator-based

    3. May need a way to allow user to tell us which approach to use. That might be the explicit option.

  3. Insert statements need to be altered to include the tenant identifier

  4. All selects need to be altered to add predicate condition based on tenant identifier.

    1. Allow switch to say whether this is done as a literal versus done as a JDBC parameter. This has been requested couple of times in regards filters as well to deal with database partitions and database query optimizers that need the partition value to be a literal.

All persistence context and second level cache related keys are already handled in the first phase.

Environment

None

Activity

Show:
Sri
July 12, 2017, 5:52 AM
Edited

Thanks for the workaround. I just implemented it (using discriminator field) for demo purpose and might be helpful for others. Here is the link:
https://github.com/ramsrib/multi-tenant-app-demo

RLS looks interesting, but it might complicate the design little bit. Like you said, most applications will not have one-to-one mapping for app user to db user. So, you need to use signed session variable.

Kedar Raybagkar
February 27, 2018, 6:46 PM
Edited

To enable the filter as well as L2 caching for Collections what if we change the following classes as indicated below? it worked for me but I am not sure where all areas it affects. I could see different query output for different filters and all of them getting cached.

Class CollectionLoadContext
method: private void addCollectionToCache(final LoadingCollectionEntry lce, final CollectionPersister persister) {
..
Just comment the following lines..
{{ if ( !session.getLoadQueryInfluencers().getEnabledFilters().isEmpty() &&
persister.isAffectedByEnabledFilters( session ) ) {
// some filters affecting the collection are enabled on the session, so do not do the put into the cache.
if ( debugEnabled ) {
LOG.debug( "Refusing to add to cache due to enabled filters" );
}
// todo : add the notion of enabled filters to the cache key to differentiate filtered collections from
// non-filtered;
// DefaultInitializeCollectionEventHandler.initializeCollectionFromCache() (which makes sure to not read
// from
// cache with enabled filters).
// EARLY EXIT!!!!!
return;
}}}

And inside DefaultInitializeCollectionEventListener

method: private boolean initializeCollectionFromCache(
final Serializable id,
final CollectionPersister persister,
final PersistentCollection collection,
final SessionImplementor source) {

comment the following lines.

{{ // if ( !source.getLoadQueryInfluencers().getEnabledFilters().isEmpty()
// && persister.isAffectedByEnabledFilters( source ) ) {
// LOG.trace( "Disregarding cached version (if any) of collection due to enabled filters" );
// return false;
// }}}
We created TenantAwareSession interface and then added setTenantIdentifier(String ..) method and then after getting the session we call setTenantIdentifier on it. That way the cache key generated is with respect to the tenant identifier.

Jonathan Shultis
September 28, 2018, 5:13 PM

I would rather have a solution to HHH-3890. That would be more flexible than any one model of multitenancy. More work for me, but at least it will do what I need it to do, not what somebody else thinks it should do.

Rodrigo Schieck
September 28, 2018, 5:34 PM
Edited

I'm currently using Filter to do this, but it's not very practical because you need an interceptor to always activate it.

Szymon Tarnowski
December 20, 2020, 12:33 PM
Edited

Hello,

I have a question related to the solution that uses Row Security Policies in Postgres.
We did in one project the Hibernate integration with RLS.
After that project closed, we decided to open an open-source project.
Currently, only DDL statements builder is released only (
There is a POC for integration with Hibernate 4 and Spring Boot (
And I have a question about integration with Hibernate 5 about what would be a better approach.
Does integration should be done with the usage of the "org.hibernate.tool.schema.internal.HibernateSchemaManagementTool" type, or is there an easy way to do this since version 5?
I think that I saw posts where it was mention that there is some extension mechanism, but I can't find it now.
Or It would be better to implement integration just like it is done in the hibernate envers module?

Assignee

Jonathan Shultis

Reporter

Steve Ebersole

Fix versions

Labels

backPortable

None

Suitable for new contributors

None

Requires Release Note

None

Pull Request

None

backportDecision

None

Components

Priority

Major
Configure