HHH-16592 error when @MapsId refers to id property with @Column mappings

This commit is contained in:
Gavin King 2023-09-11 12:58:51 +02:00
parent 7074188875
commit c014abb0d5
8 changed files with 152 additions and 40 deletions

View File

@ -280,6 +280,7 @@ public class AnnotatedColumn {
}
else {
mappingColumn = new Column();
mappingColumn.setExplicit( !isImplicit );
redefineColumnName( columnName, propertyName, applyNamingStrategy );
mappingColumn.setLength( length );
if ( precision != null && precision > 0 ) { //relevant precision

View File

@ -316,6 +316,7 @@ public class AnnotatedJoinColumn extends AnnotatedColumn {
final String columnName = defaultColumnName( columnIndex, referencedEntity, logicalReferencedColumn );
//yuk side effect on an implicit column
setLogicalColumnName( columnName );
setImplicit( true );
setReferencedColumn( logicalReferencedColumn );
final Column mappingColumn = getMappingColumn();
initMappingColumn(
@ -335,16 +336,23 @@ public class AnnotatedJoinColumn extends AnnotatedColumn {
private String defaultColumnName(int columnIndex, PersistentClass referencedEntity, String logicalReferencedColumn) {
final AnnotatedJoinColumns parent = getParent();
// if ( parent.hasMapsId() ) {
// // infer the join column of the association
// // from the name of the mapped primary key
// // column (this is not required by the JPA
// // spec) and is arguably backwards, given
// // the name of the @MapsId annotation, but
// // it's better than just having two different
// // column names which disagree
// return parent.resolveMapsId().getValue().getColumns().get( columnIndex ).getQuotedName();
// }
if ( parent.hasMapsId() ) {
// infer the join column of the association
// from the name of the mapped primary key
// column (this is not required by the JPA
// spec) and is arguably backwards, given
// the name of the @MapsId annotation, but
// it's better than just having two different
// column names which disagree
final Column column = parent.resolveMapsId().getValue().getColumns().get( columnIndex );
// return column.getQuotedName();
if ( column.isExplicit() ) {
throw new AnnotationException( "Association '" + parent.getPropertyName()
+ "' in entity '" + parent.getPropertyHolder().getEntityName()
+ "' is annotated '@MapsId' but refers to a property '"
+ parent.getMapsId() + "' which has an explicit column mapping" );
}
}
// else {
return parent.buildDefaultColumnName( referencedEntity, logicalReferencedColumn );
// }

View File

@ -57,6 +57,7 @@ public class Column implements Selectable, Serializable, Cloneable, ColumnTypeIn
private String sqlTypeName;
private Integer sqlTypeCode;
private boolean quoted;
private boolean explicit;
int uniqueInteger;
private String comment;
private String defaultValue;
@ -117,6 +118,14 @@ public class Column implements Selectable, Serializable, Cloneable, ColumnTypeIn
}
}
public boolean isExplicit() {
return explicit;
}
public void setExplicit(boolean explicit) {
this.explicit = explicit;
}
private static boolean isQuoted(String name) {
//TODO: deprecated, remove eventually
return name != null

View File

@ -13,6 +13,7 @@ import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Test;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
@ -107,7 +108,6 @@ public class DefaultedMapsIdTest {
@IdClass(ExtensionId.class)
static class Extension {
@Id
// @Column(name = "EX_LOAN_ID")
private Long exLoanId;
@Id
@ -119,7 +119,6 @@ public class DefaultedMapsIdTest {
@ManyToOne
@MapsId("exLoanId")
// @JoinColumn(name = "EX_LOAN_ID")
private Loan loan;
}
}

View File

@ -7,6 +7,7 @@ import jakarta.persistence.Embeddable;
import jakarta.persistence.EmbeddedId;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.MapsId;
import jakarta.persistence.OneToMany;
@ -82,10 +83,9 @@ public class MapsEmbeddedIdTest {
@Embeddable
public static class ExtensionId {
// @Column(name="EX_LOAN_ID")
private Long exLoanId;
// @Column(name="EX_NO")
@Column(name="EX_NO")
private int exNo;
public ExtensionId(Long exLoanId, int exNo) {
@ -114,8 +114,6 @@ public class MapsEmbeddedIdTest {
static class Extension {
@EmbeddedId
@AttributeOverride(name = "exLoanId", column = @Column(name="EX_LOAN_ID"))
@AttributeOverride(name = "exNo", column = @Column(name="EX_NO"))
private ExtensionId id;
@Column(name = "EX_EXTENSION_DAYS")
@ -123,7 +121,7 @@ public class MapsEmbeddedIdTest {
@ManyToOne
@MapsId("exLoanId")
// @JoinColumn(name = "EX_LOAN_ID")
@JoinColumn(name = "EX_LOAN_ID")
private Loan loan;
}
}

View File

@ -1,10 +1,12 @@
package org.hibernate.orm.test.annotations.mapsid;
import jakarta.persistence.AttributeOverride;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import jakarta.persistence.EmbeddedId;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.IdClass;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.MapsId;
@ -23,27 +25,27 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
@SessionFactory
@DomainModel(annotatedClasses = {MapsIdSpecTest.Loan.class, MapsIdSpecTest.Extension.class})
public class MapsIdSpecTest {
@DomainModel(annotatedClasses = {MapsEmbeddedIdWithOverrideTest.Loan.class, MapsEmbeddedIdWithOverrideTest.ExtensionId.class, MapsEmbeddedIdWithOverrideTest.Extension.class})
public class MapsEmbeddedIdWithOverrideTest {
@Test void test(SessionFactoryScope scope) {
ExtensionId eid = scope.fromTransaction( s -> {
Loan loan = new Loan();
loan.id = 999L;
ExtensionId exid = new ExtensionId(loan.id, 1);
Extension extension = new Extension();
extension.exLoanId = loan.id;
extension.id = exid;
extension.loan = loan;
extension.exNo = 1;
extension.exExtensionDays = 30;
loan.extensions.add(extension);
exid = new ExtensionId(loan.id, 2);
extension = new Extension();
extension.exLoanId = loan.id;
extension.id = exid;
extension.loan = loan;
extension.exNo = 2;
extension.exExtensionDays = 14;
loan.extensions.add(extension);
s.persist(loan);
return new ExtensionId(extension.exLoanId, extension.exNo );
return exid;
});
scope.inSession( s -> {
List<Extension> extensions = s.createQuery("from Extension", Extension.class).getResultList();
@ -52,16 +54,16 @@ public class MapsIdSpecTest {
scope.inSession( s -> {
Extension extension = s.find(Extension.class, eid);
assertEquals(14, extension.exExtensionDays);
assertEquals(2, extension.exNo);
assertEquals(999L, extension.exLoanId);
assertEquals(2, extension.id.exNo);
assertEquals(999L, extension.id.exLoanId);
assertNotNull( extension.loan );
});
scope.inSession( s -> {
Loan loan = s.find(Loan.class, eid.exLoanId);
Extension extension = loan.extensions.get(0);
assertEquals(1, extension.exNo);
assertEquals(1, extension.id.exNo);
assertEquals(30, extension.exExtensionDays);
assertEquals(999L, extension.exLoanId);
assertEquals(999L, extension.id.exLoanId);
assertEquals(loan, extension.loan);
});
}
@ -78,8 +80,11 @@ public class MapsIdSpecTest {
private List<Extension> extensions = new ArrayList<>();
}
static class ExtensionId {
@Embeddable
public static class ExtensionId {
private Long exLoanId;
private int exNo;
public ExtensionId(Long exLoanId, int exNo) {
@ -105,15 +110,11 @@ public class MapsIdSpecTest {
}
@Entity(name = "Extension")
@IdClass(ExtensionId.class)
static class Extension {
@Id
// @Column(name = "EX_LOAN_ID")
private Long exLoanId;
@Id
@Column(name = "EX_NO")
private int exNo;
@EmbeddedId
@AttributeOverride(name = "exNo", column = @Column(name="EX_NO"))
private ExtensionId id;
@Column(name = "EX_EXTENSION_DAYS")
private int exExtensionDays;

View File

@ -5,6 +5,7 @@ import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.IdClass;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.MapsId;
import jakarta.persistence.OneToMany;
@ -13,7 +14,6 @@ import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Test;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
@ -108,7 +108,6 @@ public class MapsIdTest {
@IdClass(ExtensionId.class)
static class Extension {
@Id
@Column(name = "EX_LOAN_ID") //TODO: this should really cause an error
private Long exLoanId;
@Id
@ -120,7 +119,7 @@ public class MapsIdTest {
@ManyToOne
@MapsId("exLoanId")
// @JoinColumn(name = "EX_LOAN_ID")
@JoinColumn(name = "EX_LOAN_ID")
private Loan loan;
}
}

View File

@ -0,0 +1,97 @@
package org.hibernate.orm.test.annotations.mapsid;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.MapsId;
import jakarta.persistence.OneToMany;
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.Test;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
@SessionFactory
@DomainModel(annotatedClasses = {NoIdClassMapsIdTest.Loan.class, NoIdClassMapsIdTest.Extension.class})
public class NoIdClassMapsIdTest {
@Test void test(SessionFactoryScope scope) {
Extension eid = scope.fromTransaction( s -> {
Loan loan = new Loan();
loan.id = 999L;
Extension extension = new Extension();
extension.exLoanId = loan.id;
extension.loan = loan;
extension.exNo = 1;
extension.exExtensionDays = 30;
loan.extensions.add(extension);
extension = new Extension();
extension.exLoanId = loan.id;
extension.loan = loan;
extension.exNo = 2;
extension.exExtensionDays = 14;
loan.extensions.add(extension);
s.persist(loan);
return extension;
});
scope.inSession( s -> {
List<Extension> extensions = s.createQuery("from Extension", Extension.class).getResultList();
assertEquals(2, extensions.size());
} );
scope.inSession( s -> {
Extension extension = s.find(Extension.class, eid);
assertEquals(14, extension.exExtensionDays);
assertEquals(2, extension.exNo);
assertEquals(999L, extension.exLoanId);
assertNotNull( extension.loan );
});
scope.inSession( s -> {
Loan loan = s.find(Loan.class, eid.exLoanId);
Extension extension = loan.extensions.get(0);
assertEquals(1, extension.exNo);
assertEquals(30, extension.exExtensionDays);
assertEquals(999L, extension.exLoanId);
assertEquals(loan, extension.loan);
});
}
@Entity(name = "Loan")
static class Loan {
@Id
@Column(name = "LOAN_ID")
private Long id;
private BigDecimal amount = BigDecimal.ZERO;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "loan")
private List<Extension> extensions = new ArrayList<>();
}
@Entity(name = "Extension")
static class Extension {
@Id
private Long exLoanId;
@Id
@Column(name = "EX_NO")
private int exNo;
@Column(name = "EX_EXTENSION_DAYS")
private int exExtensionDays;
@ManyToOne
@MapsId("exLoanId")
@JoinColumn(name = "EX_LOAN_ID")
private Loan loan;
}
}