{"id":15295158,"url":"https://github.com/starnowski/posmulten-hibernate","last_synced_at":"2026-01-23T05:36:55.971Z","repository":{"id":37820520,"uuid":"441984278","full_name":"starnowski/posmulten-hibernate","owner":"starnowski","description":"Integration of Posmulten and Hibernate libraries","archived":false,"fork":false,"pushed_at":"2024-08-24T23:29:50.000Z","size":270,"stargazers_count":3,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-07-19T19:07:44.242Z","etag":null,"topics":["database","hibernate","multi-tenant-applications","multitenancy","postgres","rls","shared-schema"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"lgpl-2.1","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/starnowski.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-12-26T21:09:30.000Z","updated_at":"2024-08-24T23:12:53.000Z","dependencies_parsed_at":"2024-01-04T01:50:51.043Z","dependency_job_id":"bd22da39-df29-4b64-ad6e-74c168e25e96","html_url":"https://github.com/starnowski/posmulten-hibernate","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/starnowski/posmulten-hibernate","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/starnowski%2Fposmulten-hibernate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/starnowski%2Fposmulten-hibernate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/starnowski%2Fposmulten-hibernate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/starnowski%2Fposmulten-hibernate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/starnowski","download_url":"https://codeload.github.com/starnowski/posmulten-hibernate/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/starnowski%2Fposmulten-hibernate/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28681009,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-23T04:33:33.518Z","status":"ssl_error","status_checked_at":"2026-01-23T04:33:30.433Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["database","hibernate","multi-tenant-applications","multitenancy","postgres","rls","shared-schema"],"created_at":"2024-09-30T17:08:50.747Z","updated_at":"2026-01-23T05:36:55.948Z","avatar_url":"https://github.com/starnowski.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Run tests for posmulten hibernate](https://github.com/starnowski/posmulten-hibernate/actions/workflows/posmulten-hibernate.yml/badge.svg)](https://github.com/starnowski/posmulten-hibernate/actions/workflows/posmulten-hibernate.yml)\n[![Maven Central](https://img.shields.io/maven-central/v/com.github.starnowski.posmulten.hibernate/parent.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22com.github.starnowski.posmulten.hibernate%22%20AND%20a:%22common%22)\n\n# posmulten-hibernate\n\n* [Introduction](#introduction)\n    * [Difference between hibernate discriminator approach and posmulten](#difference-between-hibernate-discriminator-approach-and-posmulten)\n* [Basic usage](#basic-usage)\n    * [Maven](#maven)\n    * [Schema generation](#schema-generation)\n        * [Hibernates SessionFactory for schema creation for Hibernate 5](#hibernates-sessionfactory-for-schema-creation-for-hibernate-5)\n        * [Hibernates configuration for schema generation for Hibernate 5](#hibernates-configuration-for-schema-generation-for-hibernate-5)\n        * [Java model](#java-model)\n        * [Hibernates SessionFactory for schema creation for Hibernate 6](#hibernates-sessionfactory-for-schema-creation-for-hibernate-6)\n    * [Client communication with database for Hibernate 5](#client-communication-with-database-for-hibernate-5)\n        * [Hibernates configuration for application connection for Hibernate 5](#hibernates-configuration-for-application-connection-for-hibernate-5)\n    * [Client communication with database for Hibernate 6](#client-communication-with-database-for-hibernate-6)\n        * [Hibernates configuration for application connection for Hibernate 6](#hibernates-configuration-for-application-connection-for-hibernate-6)\n    * [Open connection for tenant for Hibernate](#open-connection-for-tenant-for-hibernate)\n* [Tenant column as part of the primary key in schema design](#tenant-column-as-part-of-the-primary-key-in-schema-design)\n    * [Java model with shared tenant column](#java-model-with-shared-tenant-column)\n        * [Hibernate issue related to overlapping foreign keys](#hibernate-issue-related-to-overlapping-foreign-keys)\n    * [Hibernates configuration for schema with shared tenant column](#hibernates-configuration-for-schema-with-shared-tenant-column)\n* [Properties](#properties)\n* [Reporting issues](#reporting-issues)\n* [Project contribution](#project-contribution)\n\n## Introduction\n\nProject is integration of Posmulten and Hibernate libraries.\n**Posmulten generates DDL statements only for the Postgres database. This means that the project is compatible only with this database engine since version 9.6.\nThe are two main goal for this project.**\nThe first is to generate DDL statements that create Multi-tenant architecture with a shared schema strategy based on the java model (currently available only for Hibernate 5).\nFor more information on how the Posmulten helps achieve this isolation strategy or what are other Multi-tenant architecture strategies, go to [project website](https://github.com/starnowski/posmulten). \nGenerated DDL statement can be executed during integration tests or used by tools that apply changes to the database, like [Liquibase](https://www.liquibase.org/) or [Flyway](https://flywaydb.org/).\nThe second goal is to help communicate between the database and its client.\n\n### Difference between hibernate discriminator approach and posmulten \n\nThere is a big difference between the newly added hibernate feature [partitioned (discriminator) data](https://docs.jboss.org/hibernate/stable/orm/userguide/html_single/Hibernate_User_Guide.html#multitenacy-discriminator)  the posmulten library on how shared schema isolation is being achieved.\nHibernate as ORM framework adds to each statement sent to database condition in which it compares tenant column for the row with tenant values stored in the current session.\nPosmulten is doing it differently. It generates DDL statements that create the Row Level Security Policy for tables that generally check if the tenant which is set for the connection is the same as the database row read or updated by SQL statement.\nBoth approaches have cons and pros.\nHibernate approach's benefit is that it can be used with other database engines.\nPosmulten can only be used for the Postgres engine.\nOn the other side Hibernate creates potencial constraint in case when there is more than one project that use database.\nIn this situation other project also need to use Hibernate.\nPosmulten gives flexibility in such situations because it generates security policies on the database level.\nThat means that other projects which use the same database do not have to use a posmulten project or even java.\nA developer needs to ensure that the correct session property is being set with the tenant identifier during [connection establishment](https://github.com/starnowski/posmulten#connecting-to-database).\n\n## Basic usage\n### Maven\nFor Hibernate 5 add project to your pom.xml\n```xml\n        \u003cdependency\u003e\n            \u003cgroupId\u003ecom.github.starnowski.posmulten.hibernate\u003c/groupId\u003e\n            \u003cartifactId\u003ehibernate5\u003c/artifactId\u003e\n            \u003cversion\u003e0.4.0\u003c/version\u003e\n        \u003c/dependency\u003e\n\n        \u003c!-- hibernate dependency --\u003e\n        \u003cdependency\u003e\n            \u003cgroupId\u003eorg.hibernate\u003c/groupId\u003e\n            \u003cartifactId\u003ehibernate-core\u003c/artifactId\u003e\n            \u003cversion\u003e5.6.3.Final\u003c/version\u003e\n        \u003c/dependency\u003e\n```\n\nFor Hibernate 6 add project to your pom.xml\n```xml\n        \u003cdependency\u003e\n            \u003cgroupId\u003ecom.github.starnowski.posmulten.hibernate\u003c/groupId\u003e\n            \u003cartifactId\u003ehibernate6\u003c/artifactId\u003e\n            \u003cversion\u003e0.4.0\u003c/version\u003e\n        \u003c/dependency\u003e\n\n        \u003c!-- hibernate dependency --\u003e\n        \u003cdependency\u003e\n            \u003cgroupId\u003eorg.hibernate\u003c/groupId\u003e\n            \u003cartifactId\u003ehibernate-core\u003c/artifactId\u003e\n            \u003cversion\u003e6.4.0.Final\u003c/version\u003e\n        \u003c/dependency\u003e\n```\n\n### Schema generation\n\nWith the help of the Hibernate ORM framework, the project creates DDL statements that generate Multi-tenant architecture with a shared schema strategy.\nThe generated DDL statements can be used during integration tests and by tools that apply changes to the database, like [Liquibase](https://www.liquibase.org/) or [Flyway](https://flywaydb.org/).\n\n#### Hibernates SessionFactory for schema creation for Hibernate 5\n\nFor Hibernate 5 use below code:\n\nTo create Hibernate session, we need to add few service initiators from project.\n\n```java\n\nimport com.github.starnowski.posmulten.hibernate.hibernate5.context.DefaultSharedSchemaContextBuilderMetadataEnricherProviderInitiator;\nimport com.github.starnowski.posmulten.hibernate.hibernate5.context.DefaultSharedSchemaContextBuilderProviderInitiator;\nimport com.github.starnowski.posmulten.hibernate.hibernate5.context.metadata.PosmultenUtilContextInitiator;\nimport com.github.starnowski.posmulten.hibernate.hibernate5.schema.SchemaCreatorStrategyContextInitiator;\nimport org.hibernate.Session;\nimport org.hibernate.SessionFactory;\nimport org.hibernate.boot.MetadataSources;\nimport org.hibernate.boot.registry.StandardServiceRegistry;\nimport org.hibernate.boot.registry.StandardServiceRegistryBuilder;\n\n//...\n\nfinal StandardServiceRegistry registry=new StandardServiceRegistryBuilder()\n        .addInitiator(new SchemaCreatorStrategyContextInitiator())\n        .addInitiator(new DefaultSharedSchemaContextBuilderProviderInitiator())\n        .addInitiator(new DefaultSharedSchemaContextBuilderMetadataEnricherProviderInitiator())\n        .addInitiator(new PosmultenUtilContextInitiator())\n        .configure(\"hibernate.schema-creator.cfg.xml\")\n        .build();\n\n        SessionFactory factory=new MetadataSources(registry)\n        .buildMetadata().buildSessionFactory();\n```\n\n#### Hibernates configuration for schema generation for Hibernate 5\nTo hibernate configuration there need to be added few properties.\n\n_hibernate.schema-creator.cfg.xml_\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\" ?\u003e\n\u003chibernate-configuration xmlns=\"http://www.hibernate.org/xsd/orm/cfg\"\u003e\n    \u003csession-factory\u003e\n        \u003c!-- ... --\u003e\n        \u003cproperty name=\"hbm2ddl.auto\"\u003ecreate-drop\u003c/property\u003e \u003c!-- create, create-drop --\u003e\n        \u003cproperty name=\"schema_management_tool\"\u003e\n            com.github.starnowski.posmulten.hibernate.hibernate5.schema.PosmultenSchemaManagementTool\n        \u003c/property\u003e\n        \u003cproperty name=\"posmulten.grantee\"\u003eposmhib4-user\u003c/property\u003e\n        \u003c!-- ... --\u003e\n    \u003c/session-factory\u003e\n\u003c/hibernate-configuration\u003e\n```\n\nThe PosmultenSchemaManagementTool type needs to be set as a schema management tool by setting its package name with the property \"schema_management_tool\".\nThe configuration also requires setting the user to which Posmulten will generate constraints that provide the expected isolation level.\nThis should be the same user used by the application for normal [communication](#client-communication-with-database) with the database\n\n**Grantee and schema creation user can be the same (database owner). There might be a little harder with setting data for tests.**\n\n#### Java model\n\nBy default, all tables with Hibernate or JPA annotations are treated as non-multitenant.\nThat is why each table that is supposed to be multi-tenant should contain the annotation \"TenantTable\".\n\n```java\n\nimport com.github.starnowski.posmulten.hibernate.hibernate5.TenantTable;\n\nimport javax.persistence.*;\n\n@Table(name = \"user_info\")\n@TenantTable\npublic class User {\n\n    @Id\n    @GeneratedValue\n    @Column(name = \"user_id\")\n    private UUID userId;\n    private String username;\n    private String password;\n    @OneToMany(mappedBy = \"user\")\n    private Set\u003cUserRole\u003e roles;\n    @OneToMany(mappedBy = \"author\")\n    private Set\u003cPost\u003e posts;\n}\n\n```\n\nThe multi-tenant table can have a relation to the non-multitenant table.\n\n#### Hibernates SessionFactory for schema creation for Hibernate 6\n\nImportant! Module for integration with Hibernate 6 does not have implemented generation of DDL statements based on Java model right now.\nInstead of that it required to attach configuration file that below:\n```yaml\ndefault_schema: \"{{template_schema_value}}\"\ncurrent_tenant_id_property_type:  \"VARCHAR(255)\"\ncurrent_tenant_id_property: \"pos.c.ten\"\nget_current_tenant_id_function_name: \"get_ten_id\"\nset_current_tenant_id_function_name: \"set_tenant\"\nequals_current_tenant_identifier_function_name: \"equals_cur_tenant\"\ntenant_has_authorities_function_name: \"_tenant_hast_auth\"\nforce_row_level_security_for_table_owner: false\ndefault_tenant_id_column: \"tenant_id\"\ngrantee: \"{{template_user_grantee}}\"\nset_current_tenant_identifier_as_default_value_for_tenant_column_in_all_tables: true\nvalid_tenant_value_constraint:\n  is_tenant_valid_function_name:  is_t_valid\n  is_tenant_valid_constraint_name:  \"is_tenant_valid_constraint_sdfa\"\n  tenant_identifiers_blacklist:\n    - invalid_tenant\n    - \"Some strange tenant ID\"\ntables:\n  - name: user_info\n    rls_policy:\n      name: users_table_rls_policy\n      tenant_column:  tenant_id\n      create_tenant_column_for_table: true\n      primary_key_definition:\n        name_for_function_that_checks_if_record_exists_in_table: \"is_user_exists\"\n        pk_columns_name_to_type:\n          user_id: uuid\n  - name: user_role\n    rls_policy:\n      name: \"user_role_table_rls_policy\"\n      tenant_column:  tenant_id\n      create_tenant_column_for_table: true\n      primary_key_definition:\n        name_for_function_that_checks_if_record_exists_in_table: \"is_user_role_exists\"\n        pk_columns_name_to_type:\n          id: bigint\n  - name: posts\n    rls_policy:\n      name: \"posts_table_rls_policy\"\n      tenant_column:  tenant_id\n      create_tenant_column_for_table: true\n      primary_key_definition:\n        name_for_function_that_checks_if_record_exists_in_table: \"is_posts_exists\"\n        pk_columns_name_to_type:\n          id: bigint\n    foreign_keys:\n      - constraint_name:  \"user_info_tenant_constraint\"\n        table_name: user_info\n        foreign_key_primary_key_columns_mappings:\n          userId:  user_id\n//...\n```\nTo see full configuration go to [link](./hibernate6-functional-tests/src/test/resources/integration-tests-configuration.yaml)\nBesides that you need to add maven dependency as below:\n\n```xml\n        \u003cdependency\u003e\n            \u003cgroupId\u003ecom.github.starnowski.posmulten.configuration\u003c/groupId\u003e\n            \u003cartifactId\u003econfiguration-yaml-interpreter\u003c/artifactId\u003e\n            \u003cversion\u003e0.9.0\u003c/version\u003e\n            \u003cscope\u003etest\u003c/scope\u003e\n        \u003c/dependency\u003e\n```\n\nTo create Hibernate session, we need to add few service initiators from project.\n\n```java\n\nimport com.github.starnowski.posmulten.hibernate.hibernate6.connection.SharedSchemaConnectionProviderInitiatorAdapter;\nimport com.github.starnowski.posmulten.hibernate.hibernate6.context.SharedSchemaContextProvider;\nimport com.github.starnowski.posmulten.hibernate.hibernate6.context.SharedSchemaContextProviderInitiator;\nimport com.github.starnowski.posmulten.hibernate.test.utils.MapBuilder;\nimport com.github.starnowski.posmulten.postgresql.core.context.ISharedSchemaContext;\nimport com.github.starnowski.posmulten.postgresql.core.context.decorator.DefaultDecoratorContext;\nimport com.github.starnowski.posmulten.postgresql.core.db.DatabaseOperationExecutor;\nimport com.github.starnowski.posmulten.postgresql.core.db.operations.exceptions.ValidationDatabaseOperationsException;\nimport org.hibernate.Session;\nimport org.hibernate.SessionFactory;\nimport org.hibernate.boot.MetadataSources;\nimport org.hibernate.boot.registry.StandardServiceRegistry;\nimport org.hibernate.boot.registry.StandardServiceRegistryBuilder;\n\n//...\n\nfinal StandardServiceRegistry registry = new StandardServiceRegistryBuilder()\n        .addInitiator(new SharedSchemaContextProviderInitiator(this.getClass().getResource(\"/integration-tests-configuration.yaml\").getPath(), DefaultDecoratorContext.builder()\n        .withReplaceCharactersMap(MapBuilder.mapBuilder().put(\"{{template_schema_value}}\", \"public\")\n        .put(\"{{template_user_grantee}}\", \"posmhib4-user\").build()).build()))\n        .configure(\"hibernate.schema-creator.cfg.xml\")\n        .build();\n\n        SessionFactory factory = new MetadataSources(registry)\n        .buildMetadata().buildSessionFactory();\n```\n\n### Client communication with database for Hibernate 5\n\nTo create Hibernate session, we need to add few service initiators from project.\n\n```java\nimport com.github.starnowski.posmulten.hibernate.hibernate5.connections.CurrentTenantPreparedStatementSetterInitiator;\nimport com.github.starnowski.posmulten.hibernate.hibernate5.connections.SharedSchemaConnectionProviderInitiatorAdapter;\nimport com.github.starnowski.posmulten.hibernate.hibernate5.context.DefaultSharedSchemaContextBuilderProviderInitiator;\nimport org.hibernate.Session;\nimport org.hibernate.SessionFactory;\nimport org.hibernate.boot.MetadataSources;\nimport org.hibernate.boot.registry.StandardServiceRegistry;\nimport org.hibernate.boot.registry.StandardServiceRegistryBuilder;\n\n    SessionFactory getPrimarySessionFactory(){\nfinal StandardServiceRegistry registry=new StandardServiceRegistryBuilder()\n        .addInitiator(new SharedSchemaConnectionProviderInitiatorAdapter())\n        .addInitiator(new DefaultSharedSchemaContextBuilderProviderInitiator())\n        .addInitiator(new CurrentTenantPreparedStatementSetterInitiator())\n        .addInitiator(new Hibernate5ContextSupplierInitiator()) // Not required\n        .configure() // configures settings from hibernate.cfg.xml\n        .build();\n\n        SessionFactory factory=new MetadataSources(registry)\n        .buildMetadata().buildSessionFactory();\n        return factory;\n        }\n```\n\n#### Hibernates configuration for application connection for Hibernate 5\nFor correct client communication with database to hibernate configuration there need to be added few properties.\n\n_hibernate.cfg.xml_\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\" ?\u003e\n\u003chibernate-configuration xmlns=\"http://www.hibernate.org/xsd/orm/cfg\"\u003e\n    \u003csession-factory\u003e\n        \u003c!-- ... --\u003e\n        \u003cproperty name=\"hibernate.multiTenancy\"\u003eSCHEMA\u003c/property\u003e\n        \u003cproperty name=\"hibernate.multi_tenant_connection_provider\"\u003e\n            com.github.starnowski.posmulten.hibernate.hibernate5.connections.SharedSchemaMultiTenantConnectionProvider\n        \u003c/property\u003e\n        \u003cproperty name=\"hibernate.tenant_identifier_resolver\"\u003e\n            com.github.starnowski.posmulten.hibernate.hibernate5.CurrentTenantIdentifierResolverImpl\n        \u003c/property\u003e\n        \u003cproperty name=\"posmulten.schema.builder.provider\"\u003elightweight\u003c/property\u003e\n        \u003c!-- ... --\u003e\n    \u003c/session-factory\u003e\n\u003c/hibernate-configuration\u003e\n```\n\nFor correct behavior, the posmulten integration uses the \"SCHEMA\" strategy which is why it is required to specify this value for the \"hibernate.multiTenancy\" property.\nThere are two other components that need to be specified:\n    -   \"com.github.starnowski.posmulten.hibernate.hibernate5.connections.SharedSchemaMultiTenantConnectionProvider\" as \"hibernate.multi_tenant_connection_provider\"\n    -   \"com.github.starnowski.posmulten.hibernate.hibernate5.CurrentTenantIdentifierResolverImpl\" as \"hibernate.tenant_identifier_resolver\"\nAnd last but not least to have fewer things to set up we have to specify the property \"posmulten.schema.builder.provider\" with value [\"lightweight\"](#lightweight).\nBy default configuration context used for session factory initialization is [\"full\"](#full).\n\n### Client communication with database for Hibernate 6\n\nTo create Hibernate session, we need to add few service initiators from project.\n\n```java\nimport com.github.starnowski.posmulten.hibernate.hibernate6.connection.SharedSchemaConnectionProviderInitiatorAdapter;\nimport com.github.starnowski.posmulten.hibernate.hibernate6.context.SharedSchemaContextProvider;\nimport com.github.starnowski.posmulten.hibernate.hibernate6.context.SharedSchemaContextProviderInitiator;\nimport com.github.starnowski.posmulten.hibernate.test.utils.MapBuilder;\nimport com.github.starnowski.posmulten.postgresql.core.context.ISharedSchemaContext;\nimport com.github.starnowski.posmulten.postgresql.core.context.decorator.DefaultDecoratorContext;\nimport com.github.starnowski.posmulten.postgresql.core.db.DatabaseOperationExecutor;\nimport com.github.starnowski.posmulten.postgresql.core.db.operations.exceptions.ValidationDatabaseOperationsException;\nimport org.hibernate.Session;\nimport org.hibernate.SessionFactory;\nimport org.hibernate.boot.MetadataSources;\nimport org.hibernate.boot.registry.StandardServiceRegistry;\nimport org.hibernate.boot.registry.StandardServiceRegistryBuilder;\n\n SessionFactory getPrimarySessionFactory() {\n    final StandardServiceRegistry registry = new StandardServiceRegistryBuilder()\n            .addInitiator(new SharedSchemaConnectionProviderInitiatorAdapter())\n            .addInitiator(new Hibernate6ContextSupplierInitiator())//No required\n            .addInitiator(new SharedSchemaContextProviderInitiator(this.getClass().getResource(\"/integration-tests-configuration.yaml\").getPath(), DefaultDecoratorContext.builder()\n            .withReplaceCharactersMap(MapBuilder.mapBuilder().put(\"{{template_schema_value}}\", \"public\")\n            .put(\"{{template_user_grantee}}\", \"posmhib4-user\").build()).build()))\n    //                .addInitiator(new CurrentTenantPreparedStatementSetterInitiator())\n            .configure() // configures settings from hibernate.cfg.xml\n            .build();\n    \n            SessionFactory factory = new MetadataSources(registry)\n            .buildMetadata().buildSessionFactory();\n            return factory;\n        }\n```\n\n#### Hibernates configuration for application connection for Hibernate 6\nFor correct client communication with database to hibernate configuration there need to be added few properties.\n\n_hibernate.cfg.xml_\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\" ?\u003e\n\u003chibernate-configuration xmlns=\"http://www.hibernate.org/xsd/orm/cfg\"\u003e\n    \u003csession-factory\u003e\n        \u003c!-- ... --\u003e\n        \u003cproperty name=\"hibernate.multiTenancy\"\u003eSCHEMA\u003c/property\u003e\n        \u003cproperty name=\"hibernate.multi_tenant_connection_provider\"\u003ecom.github.starnowski.posmulten.hibernate.hibernate6.connection.SharedSchemaMultiTenantConnectionProvider\u003c/property\u003e\n        \u003cproperty name=\"hibernate.tenant_identifier_resolver\"\u003ecom.github.starnowski.posmulten.hibernate.hibernate6.CurrentTenantIdentifierResolverImpl\u003c/property\u003e\n        \u003c!-- ... --\u003e\n    \u003c/session-factory\u003e\n\u003c/hibernate-configuration\u003e\n```\n\nFor correct behavior, the posmulten integration uses the \"SCHEMA\" strategy which is why it is required to specify this value for the \"hibernate.multiTenancy\" property.\nThere are two other components that need to be specified:\n-   \"com.github.starnowski.posmulten.hibernate.hibernate6.connection.SharedSchemaMultiTenantConnectionProvider\" as \"hibernate.multi_tenant_connection_provider\"\n-   \"com.github.starnowski.posmulten.hibernate.hibernate6.CurrentTenantIdentifierResolverImpl\" as \"hibernate.tenant_identifier_resolver\"\n\n### Open connection for tenant for Hibernate\nBelow there is an example how connect and execute operation for tenant \"Ten1\".\n\n```java\n\n    private Session openPrimarySession() {\n            return primarySessionFactory.openSession();\n    }\n\n    private User findUserByUsername(Session session, String username) {\n        Query\u003cUser\u003e query = session.createQuery(\"FROM User as user WHERE user.username = :username\", User.class);\n        query.setParameter(\"username\", username);\n        return query.uniqueResult();\n    }\n\n    void test() {\n        setCurrentTenant(\"Ten1\");\n        try (Session session = openPrimarySession()) {\n             // WHEN\n            User current =  findUserByUsername(session, \"Simon\");\n            \n            // THEN\n            assertThat(current).isNotNull();\n            assertThat(current.getUsername()).isEqualTo(\"Simon\");\n        }\n            \n        setCurrentTenant(tt);\n        try (Session session = openPrimarySession()) {\n            Transaction transaction = session.beginTransaction();\n\n            // WHEN\n            int numberOfDeleteRecords = session.createNativeQuery(String.format(\"UPDATE user_info SET password = 'YYY' WHERE username = '%s'\", \"Simon\")).executeUpdate();\n            session.flush();\n            transaction.commit();\n        }\n\n    }\n```\n\n## Tenant column as part of the primary key in schema design\n\nThe [basic usage](#basic-usage) section described schema example assumes that the tenant discriminator column is not part of the primary key.\nThe main disadvantage of this approach might come to light when there will be project requirements for migrating tenant data between databases.\nIf there is no such requirement for the project then it is okay to have a primary key without a tenant column and not included it in the unique constraint for the primary key.\nIn case when we have such requirements besides the primary key we need to make sure that foreign key columns do not contain redundant columns in their reference to the tenant column from a different table.\nForeign keys have to share the tenant column with primary keys.\nGenerally, all unique constraints (except for dictionary tables that do not have to be multi-tenant) should be aware of the tenant column.\n\n### Java model with shared tenant column\n\nTo better demonstrate the shared tenant column between keys, we will create two classes representing composite keys.\n\n```java\nimport javax.persistence.Embeddable;\nimport java.io.Serializable;\n\n@Embeddable\npublic class StringPrimaryKey implements Serializable {\n\n    private String stringKey;\n\n    private String tenant;\n\n    // Getters, Setters, Equals and HashCode\n}\n```\n\n```java\nimport javax.persistence.Embeddable;\nimport java.io.Serializable;\n\n@Embeddable\npublic class LongPrimaryKey implements Serializable {\n\n    private Long key;\n    private String tenant;\n\n    // Getters, Setters, Equals and HashCode\n}\n```\n\nBelow there is an example of two entities with shared tenant column\n\n```java\nimport com.github.starnowski.posmulten.hibernate.hibernate5.TenantTable;\nimport org.hibernate.annotations.JoinColumnOrFormula;\nimport org.hibernate.annotations.JoinColumnsOrFormulas;\n\nimport javax.persistence.*;\n\n@Table(name = \"user_info_nonforeignkeyconstraint\")\n@TenantTable(tenantIdColumn = \"tenant\")\npublic class User {\n\n    @EmbeddedId\n    @AttributeOverride(name = \"stringKey\", column = @Column(name = \"user_id\"))\n    @AttributeOverride(name = \"tenant\", column = @Column(name = \"tenant\", insertable = false, updatable = false))\n    private StringPrimaryKey primaryKey;\n    private String username;\n    private String password;\n\n    @OneToMany(mappedBy = \"author\", fetch = LAZY)\n    @JoinColumnsOrFormulas(value = {\n            //name --\u003e Post column, referencedColumnName -- User column\n            @JoinColumnOrFormula(column = @JoinColumn(name = \"tenant_id\", referencedColumnName = \"tenant\")),\n            @JoinColumnOrFormula(column = @JoinColumn(name = \"user_id\", referencedColumnName = \"user_id\"))\n    })\n    private Set\u003cPost\u003e posts;\n\n    // Getters and Setters\n}\n```\n\n```java\nimport com.github.starnowski.posmulten.hibernate.hibernate5.TenantTable;\nimport org.hibernate.annotations.JoinColumnOrFormula;\nimport org.hibernate.annotations.JoinColumnsOrFormulas;\nimport org.hibernate.annotations.JoinFormula;\n\nimport javax.persistence.*;\n\n@Table(name = \"posts_nonforeignkeyconstraint\")\n@TenantTable\n@IdClass(LongPrimaryKey.class)\npublic class Post {\n\n    @Id\n    @GeneratedValue\n    private long key;\n    @Id\n    @Column(name = \"tenant_id\", insertable = false, updatable = false)\n    private String tenant;\n\n    @ManyToOne\n    @JoinColumnsOrFormulas(value = {\n            @JoinColumnOrFormula(formula = @JoinFormula(value = \"tenant_id\", referencedColumnName = \"tenant\")),\n            @JoinColumnOrFormula(column = @JoinColumn(name = \"user_id\", referencedColumnName = \"user_id\"))\n    })\n    private User author;\n\n    @Column(columnDefinition = \"text\")\n    private String text;\n\n    // Getters and Setters\n}\n```\n\n#### Hibernate issue related to overlapping foreign keys\n\nHibernate has known issue related to [overlapping foreign keys](https://hibernate.atlassian.net/browse/HHH-6221).\nUsage of JoinColumnsOrFormulas annotation is a workaround for this issue but it has some drawbacks.\nOne of them is that the hibernate does not generates foreign key constraint for such declaration.\nWe need to add these statements manually in the import.sql file to solve this problem.\n\n```sql\n-- This is required because hibernate does not creates foreign key constraint for JoinColumnsOrFormulas annotation\nALTER TABLE posts_nonforeignkeyconstraint ADD CONSTRAINT fk_posts_users_author_manual_added FOREIGN KEY (user_id, tenant_id) REFERENCES user_info_nonforeignkeyconstraint;\n```\n\n**Important!** There is a plan to add  [features](https://github.com/starnowski/posmulten-hibernate/issues/17) to this project to solve this problem.\n\n#### Hibernates configuration for schema with shared tenant column\n\nConfiguration looks almost the same as for basic [use case](#hibernates-configuration-for-schema-generation) with one additional property.\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\" ?\u003e\n\u003chibernate-configuration xmlns=\"http://www.hibernate.org/xsd/orm/cfg\"\u003e\n    \u003csession-factory\u003e\n        \u003c!-- ... --\u003e\n        \u003cproperty name=\"posmulten.foreignkey.constraint.ignore\"\u003etrue\u003c/property\u003e\n        \u003c!-- ... --\u003e\n    \u003c/session-factory\u003e\n\u003c/hibernate-configuration\u003e\n```\n\nBy default, the project adds a constraint that checks if a foreign key belongs to the current tenant.\nIn a situation when foreign and primary key shares the same tenant column which is monitored by RLS policy created by posmulten, such constraint is redundant.\nThe \"posmulten.foreignkey.constraint.ignore\" property allows to ignore of adding this constraint for foreign key.\n\n## Properties\n\n**General properties**\n\nBelow properties can be applied in both modules for hibernate 5 and hibernate 6.\nIt is required to add object Hibernate5ContextSupplierInitiator (hibernate5) or Hibernate6ContextSupplierInitiator (hibernate6) during initialization object of type StandardServiceRegistry\n\n| Property name | Type    | Required | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |\n|---------------|---------|----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n|hibernate.posmulten.tenant.id.default.id | Boolean | No       | Default tenant id which is going to be set when acquiring database connection. It is not necessary to set this property because the connection at the end is going to be set for the correct tenant. It is worth to set passed value together with hibernate.posmulten.tenant.id.values.blacklist or [list of invalid tenant identifier values](https://github.com/starnowski/posmulten/tree/master/configuration-parent/configuration-yaml-interpreter#setting-a-list-of-invalid-tenant-identifier-values) |\n\n\n**Important! Below properties currently are only available for module that integrates with Hibernate 5**\n\n| Property name |   Type    |   Required  |   Description |\n|---------------|-----------|---------------|---------------|\n|hibernate.posmulten.grantee |    String  |   [full](#full) |   Database user to which Posmulten will generate constraints that provide the expected isolation level. This should be the same user used by the application for normal communication with the database   |\n|hibernate.posmulten.schema.builder.provider |    String  |   No |   Configuration context used for session factory initialization. By default the [\"full\"](#full) is being used   |\n|hibernate.posmulten.foreignkey.constraint.ignore |    Boolean  |   No |   For value \"true\", the library ignores adding this constraint that checks if a foreign key belongs to the current tenant  |\n|hibernate.posmulten.tenant.id.property |    String  |   No |   Default name of column that stores tenant identifier. |\n|hibernate.posmulten.tenant.id.set.current.as.default |    Boolean  |   No |   Generate a statement that sets a default value for the tenant column in all tables. Default value is \"true\" |\n|hibernate.posmulten.tenant.id.values.blacklist |    String  |   No |   An array of invalid values for tenant identifier. The array needs to have at least one element. Ids are separated by comma |\n|hibernate.posmulten.tenant.column.java.type |    String  |   No |   Java type that represents tenant identifier which is being used in SQL statement that sets a current tenant. Available values are \"long\", \"string\" and \"custom\". The default value is \"string\". For \"custom\" there needs to be also \"hibernate.posmulten.tenant.column.java.type.custom.resolver\" property defined |\n|hibernate.posmulten.tenant.column.java.type.custom.resolver |    String  |   No |   Java type that implements com.github.starnowski.posmulten.hibernate.hibernate5.connections.ICurrentTenantPreparedStatementSetter interface which objective is to map correctly passed tenant value in prepared SQL statement |\n|hibernate.posmulten.function.getcurrenttenant.name |    String  |   No |   Name of SQL function that returns current tenant value |\n|hibernate.posmulten.function.setcurrenttenant.name |    String  |   No |   Name of SQL function that sets current tenant value |\n|hibernate.posmulten.function.equalscurrenttenantidentifier.name |    String  |   No |   Name of SQL function that checks if the identifier passed as argument is equal to the current tenant value |\n|hibernate.posmulten.function.tenanthasauthorities.name |    String  |   No |   Name of SQL function that checks if the current tenant for the database session has access to table row based on tenant column  |\n|hibernate.posmulten.metadata.table.additional.enrichers |    String  |   No |   An array of subtypes of com.github.starnowski.posmulten.hibernate.hibernate5.context.IDefaultSharedSchemaContextBuilderTableMetadataEnricher interface that will be invoked after default enrichers. The array needs to have at least one element and each element should be a full class name with a package. Types are separated by comma  |\n|hibernate.posmulten.metadata.additional.enrichers |    String  |   No |   An array of subtypes of com.github.starnowski.posmulten.hibernate.hibernate5.context.IDefaultSharedSchemaContextBuilderMetadataEnricher interface that will be invoked after default enrichers. The array needs to have at least one element and each element should be a full class name with a package. Types are separated by comma  |\n\n##### lightweight \nConfiguration context without any redundant thing that allows for the application to establish connections to the database\n\n##### full \nConfiguration context needed to set up session factory for schema creation. It also can be used by the application to establish connections to the database\n\n# Reporting issues\n* Any new issues please report in [GitHub site](https://github.com/starnowski/posmulten-hibernate/issues)\n\n# Project contribution\n* Look for open issues or create your own\n* Fork repository on Github and start applying your changes to master branch or release branch\n* Follow CONTRIBUTING.md document for coding rules\n* Create pull request\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstarnowski%2Fposmulten-hibernate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstarnowski%2Fposmulten-hibernate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstarnowski%2Fposmulten-hibernate/lists"}