Skip to content

Commit d6c1f69

Browse files
committed
HHH-17117 allow @TenantID to form part of composite key
1 parent 0dd606a commit d6c1f69

File tree

8 files changed

+260
-43
lines changed

8 files changed

+260
-43
lines changed

hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2133,7 +2133,8 @@ private void processExportableProducers() {
21332133
handleIdentifierValueBinding(
21342134
entityBinding.getIdentifier(),
21352135
dialect,
2136-
(RootClass) entityBinding
2136+
(RootClass) entityBinding,
2137+
entityBinding.getIdentifierProperty()
21372138
);
21382139

21392140
}
@@ -2146,15 +2147,14 @@ private void processExportableProducers() {
21462147
handleIdentifierValueBinding(
21472148
( (IdentifierCollection) collection ).getIdentifier(),
21482149
dialect,
2150+
null,
21492151
null
21502152
);
21512153
}
21522154
}
21532155

21542156
private void handleIdentifierValueBinding(
2155-
KeyValue identifierValueBinding,
2156-
Dialect dialect,
2157-
RootClass entityBinding) {
2157+
KeyValue identifierValueBinding, Dialect dialect, RootClass entityBinding, Property identifierProperty) {
21582158
// todo : store this result (back into the entity or into the KeyValue, maybe?)
21592159
// This process of instantiating the id-generator is called multiple times.
21602160
// It was done this way in the old code too, so no "regression" here; but
@@ -2163,7 +2163,8 @@ private void handleIdentifierValueBinding(
21632163
final Generator generator = identifierValueBinding.createGenerator(
21642164
bootstrapContext.getIdentifierGeneratorFactory(),
21652165
dialect,
2166-
entityBinding
2166+
entityBinding,
2167+
identifierProperty
21672168
);
21682169

21692170
if ( generator instanceof ExportableProducer ) {

hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,8 @@ private static Map<String, Generator> createGenerators(
467467
final Generator generator = id.createGenerator(
468468
bootstrapContext.getIdentifierGeneratorFactory(),
469469
jdbcServices.getJdbcEnvironment().getDialect(),
470-
(RootClass) model
470+
(RootClass) model,
471+
model.getIdentifierProperty()
471472
);
472473
if ( generator instanceof Configurable ) {
473474
final Configurable identifierGenerator = (Configurable) generator;

hibernate-core/src/main/java/org/hibernate/mapping/Component.java

Lines changed: 40 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -671,12 +671,19 @@ public Generator createGenerator(
671671
IdentifierGeneratorFactory identifierGeneratorFactory,
672672
Dialect dialect,
673673
RootClass rootClass) throws MappingException {
674+
return createGenerator( identifierGeneratorFactory, dialect, rootClass, rootClass.getIdentifierProperty() );
675+
}
676+
677+
@Override
678+
public Generator createGenerator(
679+
IdentifierGeneratorFactory identifierGeneratorFactory,
680+
Dialect dialect,
681+
RootClass rootClass,
682+
Property property) throws MappingException {
674683
if ( builtIdentifierGenerator == null ) {
675-
builtIdentifierGenerator = buildIdentifierGenerator(
676-
identifierGeneratorFactory,
677-
dialect,
678-
rootClass
679-
);
684+
builtIdentifierGenerator = DEFAULT_ID_GEN_STRATEGY.equals( getIdentifierGeneratorStrategy() )
685+
? buildIdentifierGenerator( identifierGeneratorFactory, dialect, rootClass )
686+
: super.createGenerator( identifierGeneratorFactory, dialect, rootClass, property );
680687
}
681688
return builtIdentifierGenerator;
682689
}
@@ -685,32 +692,10 @@ private Generator buildIdentifierGenerator(
685692
IdentifierGeneratorFactory identifierGeneratorFactory,
686693
Dialect dialect,
687694
RootClass rootClass) throws MappingException {
688-
final boolean hasCustomGenerator = ! DEFAULT_ID_GEN_STRATEGY.equals( getIdentifierGeneratorStrategy() );
689-
if ( hasCustomGenerator ) {
690-
return super.createGenerator( identifierGeneratorFactory, dialect, rootClass );
691-
}
692-
693-
final Class<?> entityClass = rootClass.getMappedClass();
694-
final Class<?> attributeDeclarer; // what class is the declarer of the composite pk attributes
695-
// IMPL NOTE : See the javadoc discussion on CompositeNestedGeneratedValueGenerator wrt the
696-
// various scenarios for which we need to account here
697-
if ( rootClass.getIdentifierMapper() != null ) {
698-
// we have the @IdClass / <composite-id mapped="true"/> case
699-
attributeDeclarer = resolveComponentClass();
700-
}
701-
else if ( rootClass.getIdentifierProperty() != null ) {
702-
// we have the "@EmbeddedId" / <composite-id name="idName"/> case
703-
attributeDeclarer = resolveComponentClass();
704-
}
705-
else {
706-
// we have the "straight up" embedded (again the Hibernate term) component identifier
707-
attributeDeclarer = entityClass;
708-
}
709-
710-
final CompositeNestedGeneratedValueGenerator.GenerationContextLocator locator =
711-
new StandardGenerationContextLocator( rootClass.getEntityName() );
712-
final CompositeNestedGeneratedValueGenerator generator =
713-
new CompositeNestedGeneratedValueGenerator( locator, getType() );
695+
final CompositeNestedGeneratedValueGenerator generator = new CompositeNestedGeneratedValueGenerator(
696+
new StandardGenerationContextLocator( rootClass.getEntityName() ),
697+
getType()
698+
);
714699

715700
final List<Property> properties = getProperties();
716701
for ( int i = 0; i < properties.size(); i++ ) {
@@ -723,15 +708,37 @@ else if ( rootClass.getIdentifierProperty() != null ) {
723708
// skip any 'assigned' generators, they would have been handled by
724709
// the StandardGenerationContextLocator
725710
generator.addGeneratedValuePlan( new ValueGenerationPlan(
726-
value.createGenerator( identifierGeneratorFactory, dialect, rootClass ),
727-
getType().isMutable() ? injector( property, attributeDeclarer ) : null,
711+
value.createGenerator( identifierGeneratorFactory, dialect, rootClass, property ),
712+
getType().isMutable() ? injector( property, getAttributeDeclarer( rootClass ) ) : null,
728713
i
729714
) );
730715
}
731716
}
732717
}
733718
return generator;
734719
}
720+
/**
721+
* Return the class that declares the composite pk attributes,
722+
* which might be an {@code @IdClass}, an {@code @EmbeddedId},
723+
* of the entity class itself.
724+
*/
725+
private Class<?> getAttributeDeclarer(RootClass rootClass) {
726+
// See the javadoc discussion on CompositeNestedGeneratedValueGenerator
727+
// for the various scenarios we need to account for here
728+
if ( rootClass.getIdentifierMapper() != null ) {
729+
// we have the @IdClass / <composite-id mapped="true"/> case
730+
return resolveComponentClass();
731+
}
732+
else if ( rootClass.getIdentifierProperty() != null ) {
733+
// we have the "@EmbeddedId" / <composite-id name="idName"/> case
734+
return resolveComponentClass();
735+
}
736+
else {
737+
// we have the "straight up" embedded (again the Hibernate term)
738+
// component identifier: the entity class itself is the id class
739+
return rootClass.getMappedClass();
740+
}
741+
}
735742

736743
private Setter injector(Property property, Class<?> attributeDeclarer) {
737744
return property.getPropertyAccessStrategy( attributeDeclarer )

hibernate-core/src/main/java/org/hibernate/mapping/KeyValue.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,14 @@ Generator createGenerator(
3434
Dialect dialect,
3535
RootClass rootClass);
3636

37+
default Generator createGenerator(
38+
IdentifierGeneratorFactory identifierGeneratorFactory,
39+
Dialect dialect,
40+
RootClass rootClass,
41+
Property property) {
42+
return createGenerator( identifierGeneratorFactory, dialect, rootClass );
43+
}
44+
3745
/**
3846
* @deprecated Use {@link #createGenerator(IdentifierGeneratorFactory, Dialect, RootClass)} instead.
3947
* No longer used except in legacy tests.

hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -392,10 +392,19 @@ public Generator createGenerator(
392392
IdentifierGeneratorFactory identifierGeneratorFactory,
393393
Dialect dialect,
394394
RootClass rootClass) throws MappingException {
395+
return createGenerator( identifierGeneratorFactory, dialect, rootClass, rootClass.getIdentifierProperty() );
396+
}
397+
398+
@Override
399+
public Generator createGenerator(
400+
IdentifierGeneratorFactory identifierGeneratorFactory,
401+
Dialect dialect,
402+
RootClass rootClass,
403+
Property property) throws MappingException {
395404
if ( generator == null ) {
396405
if ( customIdGeneratorCreator != null ) {
397406
generator = customIdGeneratorCreator.createGenerator(
398-
new IdGeneratorCreationContext( identifierGeneratorFactory, null, null, rootClass )
407+
new IdGeneratorCreationContext( identifierGeneratorFactory, null, null, rootClass, property)
399408
);
400409
}
401410
else {
@@ -1080,12 +1089,19 @@ private class IdGeneratorCreationContext implements CustomIdGeneratorCreationCon
10801089
private final String defaultCatalog;
10811090
private final String defaultSchema;
10821091
private final RootClass rootClass;
1083-
1084-
public IdGeneratorCreationContext(IdentifierGeneratorFactory identifierGeneratorFactory, String defaultCatalog, String defaultSchema, RootClass rootClass) {
1092+
private final Property property;
1093+
1094+
public IdGeneratorCreationContext(
1095+
IdentifierGeneratorFactory identifierGeneratorFactory,
1096+
String defaultCatalog,
1097+
String defaultSchema,
1098+
RootClass rootClass,
1099+
Property property) {
10851100
this.identifierGeneratorFactory = identifierGeneratorFactory;
10861101
this.defaultCatalog = defaultCatalog;
10871102
this.defaultSchema = defaultSchema;
10881103
this.rootClass = rootClass;
1104+
this.property = property;
10891105
}
10901106

10911107
@Override
@@ -1125,7 +1141,7 @@ public PersistentClass getPersistentClass() {
11251141

11261142
@Override
11271143
public Property getProperty() {
1128-
return rootClass.getIdentifierProperty();
1144+
return property;
11291145
}
11301146

11311147
// we could add these if it helps integrate old infrastructure
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
5+
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
6+
*/
7+
package org.hibernate.orm.test.tenantidpk;
8+
9+
import jakarta.persistence.Entity;
10+
import jakarta.persistence.GeneratedValue;
11+
import jakarta.persistence.Id;
12+
import jakarta.persistence.ManyToOne;
13+
import org.hibernate.annotations.TenantId;
14+
15+
import java.util.UUID;
16+
17+
@Entity
18+
public class Account {
19+
20+
@Id @GeneratedValue Long id;
21+
22+
@Id @TenantId UUID tenantId;
23+
24+
@ManyToOne(optional = false)
25+
Client client;
26+
27+
public Account(Client client) {
28+
this.client = client;
29+
}
30+
31+
Account() {}
32+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
5+
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
6+
*/
7+
package org.hibernate.orm.test.tenantidpk;
8+
9+
import jakarta.persistence.Entity;
10+
import jakarta.persistence.GeneratedValue;
11+
import jakarta.persistence.Id;
12+
import jakarta.persistence.OneToMany;
13+
import org.hibernate.annotations.TenantId;
14+
15+
import java.util.HashSet;
16+
import java.util.Set;
17+
import java.util.UUID;
18+
19+
@Entity
20+
public class Client {
21+
@Id
22+
@GeneratedValue
23+
Long id;
24+
25+
String name;
26+
27+
@Id @TenantId
28+
UUID tenantId;
29+
30+
@OneToMany(mappedBy = "client")
31+
Set<Account> accounts = new HashSet<>();
32+
33+
public Client(String name) {
34+
this.name = name;
35+
}
36+
37+
Client() {}
38+
}
39+

0 commit comments

Comments
 (0)