diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ManyToManyCollectionPart.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ManyToManyCollectionPart.java index 9b6f9a19a8a3..c0425887f231 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ManyToManyCollectionPart.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ManyToManyCollectionPart.java @@ -398,7 +398,7 @@ else if ( getNature() == Nature.INDEX ) { } else if ( StringHelper.isNotEmpty( bootCollectionDescriptor.getMappedByProperty() ) ) { final ModelPart mappedByPart = resolveNamedTargetPart( bootCollectionDescriptor.getMappedByProperty(), getAssociatedEntityMappingType(), collectionDescriptor ); - if ( mappedByPart instanceof ToOneAttributeMapping ) { + if ( mappedByPart instanceof ToOneAttributeMapping || mappedByPart instanceof DiscriminatedAssociationAttributeMapping ) { //////////////////////////////////////////////// // E.g. // @@ -425,7 +425,7 @@ else if ( StringHelper.isNotEmpty( bootCollectionDescriptor.getMappedByProperty( final ManyToOne elementDescriptor = (ManyToOne) bootCollectionDescriptor.getElement(); assert elementDescriptor.isReferenceToPrimaryKey(); - final String collectionTableName = ( (BasicCollectionPersister) collectionDescriptor ).getTableName(); + final String collectionTableName = collectionDescriptor.getTableName(); // this fk will refer to the associated entity's id. if that id is not ready yet, delay this creation if ( getAssociatedEntityMappingType().getIdentifierMapping() == null ) { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/manytoone/ManyToOneWithAnyAndSecondaryTable.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/manytoone/ManyToOneWithAnyAndSecondaryTable.java new file mode 100644 index 000000000000..1cebd6f0eb2e --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/manytoone/ManyToOneWithAnyAndSecondaryTable.java @@ -0,0 +1,114 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.mapping.manytoone; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.OneToMany; +import jakarta.persistence.SecondaryTable; +import jakarta.persistence.Table; +import org.hibernate.annotations.Any; +import org.hibernate.annotations.AnyKeyJavaClass; +import org.hibernate.annotations.Fetch; +import org.hibernate.annotations.FetchMode; +import org.hibernate.cfg.JdbcSettings; +import org.hibernate.testing.orm.junit.EntityManagerFactoryScope; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.Jpa; +import org.hibernate.testing.orm.junit.Setting; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import static jakarta.persistence.FetchType.LAZY; + +/** + * Allows testing a @OneToMany mappedBy relationship with a @Any as the return variable and persist in secondary table. + * + * @author Vincent Bouthinon + */ +@Jpa( + annotatedClasses = { + ManyToOneWithAnyAndSecondaryTable.Actor.class, + ManyToOneWithAnyAndSecondaryTable.Contact.class + }, + integrationSettings = @Setting(name = JdbcSettings.SHOW_SQL, value = "true") +) +@JiraKey("HHH-18750") +class ManyToOneWithAnyAndSecondaryTable { + + @Test + void testMappingManyToOneMappedByAnyPersistedInSecondaryTable(EntityManagerFactoryScope scope) { + scope.inTransaction( + entityManager -> { + Actor actor = new Actor(); + actor.addToContacts( new Contact() ); + entityManager.persist( actor ); + entityManager.flush(); + entityManager.clear(); + + List actors = entityManager.createQuery( "select a from actor a", Actor.class ) + .getResultList(); + Assertions.assertEquals( actors.size(), 2 ); + } + ); + } + + + @Entity(name = "actor") + @Table(name = "TACTOR") + public static class Actor { + + @Id + @GeneratedValue + private Long id; + + @OneToMany(mappedBy = "objetMaitre", cascade = {CascadeType.ALL}) + @Fetch(FetchMode.SELECT) + private Set contacts = new HashSet<>(); + + public Set getContacts() { + return contacts; + } + + public void setContacts(Set contacts) { + this.contacts = contacts; + } + + public void addToContacts(Contact contact) { + this.contacts.add( contact ); + contact.setObjetMaitre( this ); + } + } + + @Entity(name = "contact") + @SecondaryTable(name = "TPERSONNEPHYSIQUE") + public static class Contact extends Actor { + @Id + @GeneratedValue + private Long id; + + @Any(fetch = LAZY) + @AnyKeyJavaClass(Long.class) + @JoinColumn(name = "OBJETMAITRE_ID", table = "TPERSONNEPHYSIQUE") + @Column(name = "OBJETMAITRE_ROLE") + private Actor objetMaitre; + + public Actor getObjetMaitre() { + return objetMaitre; + } + + public void setObjetMaitre(Actor objetMaitre) { + this.objetMaitre = objetMaitre; + } + } +}