HHH-15339 Add foreign key part name as target key property name for fk optimization
This commit is contained in:
parent
cc500d46e8
commit
04fd92b204
|
@ -6,7 +6,6 @@
|
|||
*/
|
||||
package org.hibernate.metamodel.mapping.internal;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
|
@ -138,6 +137,12 @@ public class EntityCollectionPart
|
|||
compositeType.getSubtypes()[0],
|
||||
creationProcess.getCreationContext().getSessionFactory()
|
||||
);
|
||||
ToOneAttributeMapping.addPrefixedPropertyNames(
|
||||
targetKeyPropertyNames,
|
||||
ForeignKeyDescriptor.PART_NAME,
|
||||
compositeType.getSubtypes()[0],
|
||||
creationProcess.getCreationContext().getSessionFactory()
|
||||
);
|
||||
}
|
||||
else {
|
||||
ToOneAttributeMapping.addPrefixedPropertyNames(
|
||||
|
@ -146,6 +151,12 @@ public class EntityCollectionPart
|
|||
propertyType,
|
||||
creationProcess.getCreationContext().getSessionFactory()
|
||||
);
|
||||
ToOneAttributeMapping.addPrefixedPropertyNames(
|
||||
targetKeyPropertyNames,
|
||||
ForeignKeyDescriptor.PART_NAME,
|
||||
propertyType,
|
||||
creationProcess.getCreationContext().getSessionFactory()
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -155,6 +166,12 @@ public class EntityCollectionPart
|
|||
propertyType,
|
||||
creationProcess.getCreationContext().getSessionFactory()
|
||||
);
|
||||
ToOneAttributeMapping.addPrefixedPropertyNames(
|
||||
targetKeyPropertyNames,
|
||||
ForeignKeyDescriptor.PART_NAME,
|
||||
propertyType,
|
||||
creationProcess.getCreationContext().getSessionFactory()
|
||||
);
|
||||
}
|
||||
this.targetKeyPropertyNames = targetKeyPropertyNames;
|
||||
}
|
||||
|
@ -172,6 +189,12 @@ public class EntityCollectionPart
|
|||
propertyType,
|
||||
creationProcess.getCreationContext().getSessionFactory()
|
||||
);
|
||||
ToOneAttributeMapping.addPrefixedPropertyNames(
|
||||
targetKeyPropertyNames,
|
||||
ForeignKeyDescriptor.PART_NAME,
|
||||
propertyType,
|
||||
creationProcess.getCreationContext().getSessionFactory()
|
||||
);
|
||||
this.targetKeyPropertyNames = targetKeyPropertyNames;
|
||||
}
|
||||
else {
|
||||
|
@ -186,6 +209,12 @@ public class EntityCollectionPart
|
|||
compositeType.getSubtypes()[0],
|
||||
creationProcess.getCreationContext().getSessionFactory()
|
||||
);
|
||||
ToOneAttributeMapping.addPrefixedPropertyNames(
|
||||
targetKeyPropertyNames,
|
||||
ForeignKeyDescriptor.PART_NAME,
|
||||
compositeType.getSubtypes()[0],
|
||||
creationProcess.getCreationContext().getSessionFactory()
|
||||
);
|
||||
this.targetKeyPropertyNames = targetKeyPropertyNames;
|
||||
}
|
||||
else {
|
||||
|
@ -199,10 +228,16 @@ public class EntityCollectionPart
|
|||
entityMappingType.getEntityPersister().getIdentifierType(),
|
||||
creationProcess.getCreationContext().getSessionFactory()
|
||||
);
|
||||
ToOneAttributeMapping.addPrefixedPropertyNames(
|
||||
targetKeyPropertyNames,
|
||||
ForeignKeyDescriptor.PART_NAME,
|
||||
entityMappingType.getEntityPersister().getIdentifierType(),
|
||||
creationProcess.getCreationContext().getSessionFactory()
|
||||
);
|
||||
this.targetKeyPropertyNames = targetKeyPropertyNames;
|
||||
}
|
||||
else {
|
||||
this.targetKeyPropertyNames = Collections.singleton( referencedPropertyName );
|
||||
this.targetKeyPropertyNames = Set.of( referencedPropertyName, ForeignKeyDescriptor.PART_NAME );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
package org.hibernate.metamodel.mapping.internal;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
@ -391,6 +390,12 @@ public class ToOneAttributeMapping
|
|||
compositeType.getSubtypes()[0],
|
||||
declaringEntityPersister.getFactory()
|
||||
);
|
||||
addPrefixedPropertyNames(
|
||||
targetKeyPropertyNames,
|
||||
ForeignKeyDescriptor.PART_NAME,
|
||||
compositeType.getSubtypes()[0],
|
||||
declaringEntityPersister.getFactory()
|
||||
);
|
||||
}
|
||||
else {
|
||||
this.targetKeyPropertyName = EntityIdentifierMapping.ROLE_LOCAL_NAME;
|
||||
|
@ -406,6 +411,12 @@ public class ToOneAttributeMapping
|
|||
propertyType,
|
||||
declaringEntityPersister.getFactory()
|
||||
);
|
||||
addPrefixedPropertyNames(
|
||||
targetKeyPropertyNames,
|
||||
ForeignKeyDescriptor.PART_NAME,
|
||||
propertyType,
|
||||
declaringEntityPersister.getFactory()
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -416,6 +427,12 @@ public class ToOneAttributeMapping
|
|||
propertyType,
|
||||
declaringEntityPersister.getFactory()
|
||||
);
|
||||
addPrefixedPropertyNames(
|
||||
targetKeyPropertyNames,
|
||||
ForeignKeyDescriptor.PART_NAME,
|
||||
propertyType,
|
||||
declaringEntityPersister.getFactory()
|
||||
);
|
||||
}
|
||||
this.targetKeyPropertyNames = targetKeyPropertyNames;
|
||||
}
|
||||
|
@ -428,6 +445,12 @@ public class ToOneAttributeMapping
|
|||
bootValue.getType(),
|
||||
declaringEntityPersister.getFactory()
|
||||
);
|
||||
addPrefixedPropertyNames(
|
||||
targetKeyPropertyNames,
|
||||
ForeignKeyDescriptor.PART_NAME,
|
||||
bootValue.getType(),
|
||||
declaringEntityPersister.getFactory()
|
||||
);
|
||||
this.targetKeyPropertyNames = targetKeyPropertyNames;
|
||||
}
|
||||
else {
|
||||
|
@ -445,6 +468,12 @@ public class ToOneAttributeMapping
|
|||
compositeType.getSubtypes()[0],
|
||||
declaringEntityPersister.getFactory()
|
||||
);
|
||||
addPrefixedPropertyNames(
|
||||
targetKeyPropertyNames,
|
||||
ForeignKeyDescriptor.PART_NAME,
|
||||
compositeType.getSubtypes()[0],
|
||||
declaringEntityPersister.getFactory()
|
||||
);
|
||||
this.targetKeyPropertyNames = targetKeyPropertyNames;
|
||||
}
|
||||
else {
|
||||
|
@ -461,10 +490,19 @@ public class ToOneAttributeMapping
|
|||
entityMappingType.getEntityPersister().getIdentifierType(),
|
||||
declaringEntityPersister.getFactory()
|
||||
);
|
||||
addPrefixedPropertyNames(
|
||||
targetKeyPropertyNames,
|
||||
ForeignKeyDescriptor.PART_NAME,
|
||||
entityMappingType.getEntityPersister().getIdentifierType(),
|
||||
declaringEntityPersister.getFactory()
|
||||
);
|
||||
this.targetKeyPropertyNames = targetKeyPropertyNames;
|
||||
}
|
||||
else {
|
||||
this.targetKeyPropertyNames = Collections.singleton( targetKeyPropertyName );
|
||||
this.targetKeyPropertyNames = Set.of(
|
||||
targetKeyPropertyName,
|
||||
ForeignKeyDescriptor.PART_NAME
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -600,16 +638,21 @@ public class ToOneAttributeMapping
|
|||
propertyName = entityType.getRHSUniqueKeyPropertyName();
|
||||
}
|
||||
final String newPrefix;
|
||||
final String newFkPrefix;
|
||||
if ( prefix == null ) {
|
||||
newPrefix = propertyName;
|
||||
newFkPrefix = ForeignKeyDescriptor.PART_NAME;
|
||||
}
|
||||
else if ( propertyName == null ) {
|
||||
newPrefix = prefix;
|
||||
newFkPrefix = prefix + "." + ForeignKeyDescriptor.PART_NAME;
|
||||
}
|
||||
else {
|
||||
newPrefix = prefix + "." + propertyName;
|
||||
newFkPrefix = prefix + "." + ForeignKeyDescriptor.PART_NAME;
|
||||
}
|
||||
addPrefixedPropertyNames( targetKeyPropertyNames, newPrefix, identifierOrUniqueKeyType, factory );
|
||||
addPrefixedPropertyNames( targetKeyPropertyNames, newFkPrefix, identifierOrUniqueKeyType, factory );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,282 @@
|
|||
package org.hibernate.orm.test.query;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jakarta.persistence.Basic;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Embeddable;
|
||||
import jakarta.persistence.EmbeddedId;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.JoinColumns;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.Tuple;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
@DomainModel(
|
||||
annotatedClasses = {
|
||||
SelectManyToOneEmbeddedIdWithKeyManyToOneQueryTest.EmbeddableTestEntity.class,
|
||||
SelectManyToOneEmbeddedIdWithKeyManyToOneQueryTest.IntIdEntity.class
|
||||
}
|
||||
)
|
||||
@SessionFactory
|
||||
@TestForIssue(jiraKey = "HHH-15339")
|
||||
public class SelectManyToOneEmbeddedIdWithKeyManyToOneQueryTest {
|
||||
|
||||
@BeforeEach
|
||||
public void setUp(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
EmbeddableTestEntity entity1, entity2;
|
||||
|
||||
IntIdEntity intIdEntity1 = new IntIdEntity("1");
|
||||
entity1 = new EmbeddableTestEntity();
|
||||
entity1.setId(new EmbeddableTestEntityId( intIdEntity1, "1"));
|
||||
|
||||
IntIdEntity intIdEntity2 = new IntIdEntity("2");
|
||||
entity2 = new EmbeddableTestEntity();
|
||||
entity2.setId(new EmbeddableTestEntityId( intIdEntity2, "2"));
|
||||
entity2.setManyToOne(entity1);
|
||||
|
||||
session.persist(intIdEntity1);
|
||||
session.persist(intIdEntity2);
|
||||
session.persist(entity1);
|
||||
session.persist(entity2);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void tearDown(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery( "update EmbeddableTestEntity e set e.manyToOne = null" ).executeUpdate();
|
||||
session.createQuery( "delete from EmbeddableTestEntity" ).executeUpdate();
|
||||
session.createQuery( "delete from IntIdEntity" ).executeUpdate();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSelectManyToOneEmbeddedIdWithKeyManyToOne(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery(
|
||||
"SELECT e.manyToOne.id " +
|
||||
"FROM EmbeddableTestEntity e ",
|
||||
Tuple.class).list();
|
||||
List<Tuple> result = session.createQuery(
|
||||
"SELECT e.manyToOne.id, i " +
|
||||
"FROM EmbeddableTestEntity e " +
|
||||
"JOIN e.manyToOne m " +
|
||||
"LEFT JOIN m.id.intIdEntity i",
|
||||
Tuple.class)
|
||||
.list();
|
||||
assertThat( result.size(), is( 1 ) );
|
||||
assertEquals(
|
||||
result.get( 0 ).get( 0, EmbeddableTestEntityId.class ).getIntIdEntity(),
|
||||
result.get( 0 ).get( 1 )
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Entity(name = "EmbeddableTestEntity")
|
||||
@Table(name = "ent")
|
||||
public static class EmbeddableTestEntity implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private EmbeddableTestEntityId id = new EmbeddableTestEntityId();
|
||||
private EmbeddableTestEntity manyToOne;
|
||||
|
||||
public EmbeddableTestEntity() {
|
||||
}
|
||||
|
||||
@EmbeddedId
|
||||
public EmbeddableTestEntityId getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(EmbeddableTestEntityId id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumns({
|
||||
@JoinColumn(name = "assoc_key", referencedColumnName = "id_key"),
|
||||
@JoinColumn(name = "assoc_fk", referencedColumnName = "id_fk")
|
||||
})
|
||||
public EmbeddableTestEntity getManyToOne() {
|
||||
return manyToOne;
|
||||
}
|
||||
|
||||
public void setManyToOne(EmbeddableTestEntity manyToOne) {
|
||||
this.manyToOne = manyToOne;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Embeddable
|
||||
public static class EmbeddableTestEntityId implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private IntIdEntity intIdEntity;
|
||||
private String key;
|
||||
|
||||
public EmbeddableTestEntityId() {
|
||||
}
|
||||
|
||||
public EmbeddableTestEntityId(IntIdEntity intIdEntity, String key) {
|
||||
this.intIdEntity = intIdEntity;
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY, optional = false)
|
||||
@JoinColumn(name = "id_fk")
|
||||
public IntIdEntity getIntIdEntity() {
|
||||
return intIdEntity;
|
||||
}
|
||||
|
||||
public void setIntIdEntity(IntIdEntity intIdEntity) {
|
||||
this.intIdEntity = intIdEntity;
|
||||
}
|
||||
|
||||
@Column(name = "id_key", length = 100)
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((intIdEntity == null) ? 0 : intIdEntity.hashCode());
|
||||
result = prime * result + ((key == null) ? 0 : key.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
EmbeddableTestEntityId other = (EmbeddableTestEntityId) obj;
|
||||
if (intIdEntity == null) {
|
||||
if (other.intIdEntity != null)
|
||||
return false;
|
||||
} else if (!intIdEntity.equals(other.intIdEntity))
|
||||
return false;
|
||||
if (key == null) {
|
||||
if (other.key != null)
|
||||
return false;
|
||||
} else if (!key.equals(other.key))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Entity(name = "IntIdEntity")
|
||||
@Table(name = "id_fkity")
|
||||
public static class IntIdEntity implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Integer id;
|
||||
private String name;
|
||||
private Integer value;
|
||||
|
||||
public IntIdEntity() {
|
||||
}
|
||||
|
||||
public IntIdEntity(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Basic(optional = false)
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Column(name = "val")
|
||||
public Integer getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(Integer value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((getId() == null) ? 0 : getId().hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof IntIdEntity)) {
|
||||
return false;
|
||||
}
|
||||
IntIdEntity other = (IntIdEntity) obj;
|
||||
if (getId() == null) {
|
||||
if (other.getId() != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!getId().equals(other.getId())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue