HHH-15767 put unique constraints where they belong on optional @OneToOne associations

this was a bug that allowed people to use @OneToOne as a regular @ManyToOne
and ... people did ... as evidenced by all these bogus tests I just fixed

this is in principle a breaking change because it breaks code that was broken
This commit is contained in:
Gavin 2022-11-26 14:43:26 +01:00 committed by Gavin King
parent 82e42ef946
commit 0253e1fe7a
12 changed files with 48 additions and 53 deletions

View File

@ -241,36 +241,32 @@ public class OneToOneSecondPass implements SecondPass {
// if not, then we need to create a many to one and formula // if not, then we need to create a many to one and formula
// but actually, since entities linked by a one to one need // but actually, since entities linked by a one to one need
// to share the same composite id class, this cannot happen // to share the same composite id class, this cannot happen
boolean rightOrder = true; // boolean rightOrder = true;
//
if ( rightOrder ) { // if ( rightOrder ) {
final ToOneFkSecondPass secondPass = new ToOneFkSecondPass( final ToOneFkSecondPass secondPass = new ToOneFkSecondPass(
oneToOne, oneToOne,
joinColumns, joinColumns,
!optional, //cannot have nullable and unique on certain DBs true,
propertyHolder.getPersistentClass(), propertyHolder.getPersistentClass(),
qualify( propertyHolder.getPath(), propertyName), qualify( propertyHolder.getPath(), propertyName),
buildingContext buildingContext
); );
secondPass.doSecondPass(persistentClasses); secondPass.doSecondPass(persistentClasses);
//no column associated since it's a one to one //no column associated since it's a one to one
propertyHolder.addProperty( property, inferredData.getDeclaringClass() ); propertyHolder.addProperty( property, inferredData.getDeclaringClass() );
} // }
// else { // else {
// this is a @ManyToOne with Formula // this is a @ManyToOne with Formula
// } // }
} }
/** /**
* Builds the <code>Join</code> instance for the mapped by side of a <i>OneToOne</i> association using * Builds the {@link Join} instance for the unowned side
* a join table. * of a {@code OneToOne} association using a join table.
* <p> * From the {@code mappedBy} side we should not create
* Note:<br/> * neither the PK, nor the FK, this is all handled from
* <ul> * the owning side.
* <li>From the mappedBy side we should not create the PK nor the FK, this is handled from the other side.</li>
* <li>This method is a dirty dupe of EntityBinder.bindSecondaryTable</li>.
* </ul>
* </p>
*/ */
private Join buildJoinFromMappedBySide(PersistentClass persistentClass, Property otherSideProperty, Join originalJoin) { private Join buildJoinFromMappedBySide(PersistentClass persistentClass, Property otherSideProperty, Join originalJoin) {
Join join = new Join(); Join join = new Join();

View File

@ -179,7 +179,7 @@ public class ToOneBinder {
final FkSecondPass secondPass = new ToOneFkSecondPass( final FkSecondPass secondPass = new ToOneFkSecondPass(
value, value,
joinColumns, joinColumns,
!optional && unique, //cannot have nullable and unique on certain DBs like Derby unique,
propertyHolder.getPersistentClass(), propertyHolder.getPersistentClass(),
fullPath, fullPath,
context context

View File

@ -61,15 +61,13 @@ public class MappedByEmbeddableTest extends BaseCoreFunctionalTestCase {
Contained contained2 = embed2.getContained(); Contained contained2 = embed2.getContained();
// switch associations: 1:1 2:2 -> 1:2 2:1 // switch associations: 1:1 2:2 -> 1:2 2:1
contained1.setContaining( null );
embed2.setContained( null );
session.flush();
embed1.setContained( contained2 ); embed1.setContained( contained2 );
contained2.setContaining( containing1 ); contained2.setContaining( containing1 );
embed2.setContained( contained1 ); embed2.setContained( contained1 );
contained1.setContaining( containing2 ); contained1.setContaining( containing2 );
session.update( containing1 );
session.update( containing2 );
session.update( contained1 );
session.update( contained2 );
} ); } );
inTransaction( session -> { inTransaction( session -> {

View File

@ -16,9 +16,7 @@ import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.orm.junit.DomainModel; import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory; import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope; import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import jakarta.persistence.CascadeType; import jakarta.persistence.CascadeType;
@ -225,10 +223,10 @@ public class SingleTableInheritancePersistTest {
private String favouriteToy; private String favouriteToy;
@OneToOne @ManyToOne
private Woman mother; private Woman mother;
@OneToOne @ManyToOne
private Man father; private Man father;
public Child() { public Child() {

View File

@ -206,10 +206,10 @@ public class TablePerClassInheritancePersistTest {
private String favouriteToy; private String favouriteToy;
@OneToOne @ManyToOne
private Woman mother; private Woman mother;
@OneToOne @ManyToOne
private Man father; private Man father;
public Child() { public Child() {

View File

@ -16,6 +16,7 @@ import jakarta.persistence.Entity;
import jakarta.persistence.Id; import jakarta.persistence.Id;
import jakarta.persistence.Inheritance; import jakarta.persistence.Inheritance;
import jakarta.persistence.InheritanceType; import jakarta.persistence.InheritanceType;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany; import jakarta.persistence.OneToMany;
import jakarta.persistence.OneToOne; import jakarta.persistence.OneToOne;
@ -166,10 +167,10 @@ public class TablePerClassInheritanceTest {
private String favouriteToy; private String favouriteToy;
@OneToOne @ManyToOne
private Woman mother; private Woman mother;
@OneToOne @ManyToOne
private Man father; private Man father;
public Child() { public Child() {

View File

@ -77,12 +77,9 @@ public class InsertOrderingSelfReferenceSingleTableInheritance {
@Test @Test
public void test2(EntityManagerFactoryScope scope) { public void test2(EntityManagerFactoryScope scope) {
scope.inTransaction( entityManager -> { scope.inTransaction( entityManager -> {
NodeLongValue aparam = new NodeLongValue(); ContentNode xa = new ContentNode(new NodeLongValue(123L), null, null );
aparam.setLongValue( 123L ); ContentNode xb = new ContentNode(new NodeLongValue(123L), null, null );
ContentNode xc = new ContentNode(new NodeLongValue(123L), xb, null );
ContentNode xa = new ContentNode( aparam, null, null );
ContentNode xb = new ContentNode( aparam, null, null );
ContentNode xc = new ContentNode( aparam, xb, null );
NodeLink nl = new NodeLink( xc ); NodeLink nl = new NodeLink( xc );
@ -118,8 +115,9 @@ public class InsertOrderingSelfReferenceSingleTableInheritance {
NodeStringValue stringVal = new NodeStringValue(); NodeStringValue stringVal = new NodeStringValue();
stringVal.setStringValue( "Node 123" ); stringVal.setStringValue( "Node 123" );
ContentNode cn0 = new ContentNode( null, null, null );
ContentNode cn1 = new ContentNode( stringVal, null, null ); ContentNode cn1 = new ContentNode( stringVal, null, null );
ContentNode cn2 = new ContentNode( longVal, cn1, null ); ContentNode cn2 = new ContentNode( longVal, cn0, null );
ContentNode cn3 = new ContentNode( null, cn1, cn2 ); ContentNode cn3 = new ContentNode( null, cn1, cn2 );
@ -345,6 +343,11 @@ public class InsertOrderingSelfReferenceSingleTableInheritance {
this.longValue = longValue; this.longValue = longValue;
} }
public NodeLongValue(Long longValue) {
super();
this.longValue = longValue;
}
public NodeLongValue() { public NodeLongValue() {
super(); super();
} }

View File

@ -54,7 +54,7 @@ public class NullablePrimaryKeyTest {
metadata, metadata,
false false
); );
String expectedMappingTableSql = "create table personAddress (address_id bigint, " + String expectedMappingTableSql = "create table personAddress (address_id bigint unique, " +
"person_id bigint not null, primary key (person_id))"; "person_id bigint not null, primary key (person_id))";
assertEquals( "Wrong SQL", expectedMappingTableSql, commands.get( 2 ) ); assertEquals( "Wrong SQL", expectedMappingTableSql, commands.get( 2 ) );

View File

@ -120,7 +120,7 @@ public class ToOneOnDeleteTest {
private String name; private String name;
@OneToOne @ManyToOne
@OnDelete(action = OnDeleteAction.CASCADE) @OnDelete(action = OnDeleteAction.CASCADE)
private Child parent; private Child parent;
} }

View File

@ -13,7 +13,6 @@ import jakarta.persistence.Id;
import jakarta.persistence.Inheritance; import jakarta.persistence.Inheritance;
import jakarta.persistence.InheritanceType; import jakarta.persistence.InheritanceType;
import jakarta.persistence.ManyToOne; import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToOne;
import jakarta.persistence.criteria.JoinType; import jakarta.persistence.criteria.JoinType;
import org.hibernate.envers.Audited; import org.hibernate.envers.Audited;
@ -131,7 +130,7 @@ public class InheritanceAssociationToOneInnerJoinTest extends BaseEnversJPAFunct
public static class EntityA { public static class EntityA {
@Id @Id
private Integer id; private Integer id;
@OneToOne @ManyToOne
private EntityD relationToD; private EntityD relationToD;
@ManyToOne @ManyToOne
private EntityC relationToC; private EntityC relationToC;

View File

@ -8,7 +8,7 @@ package org.hibernate.orm.test.envers.integration.onetoone.bidirectional;
import jakarta.persistence.Entity; import jakarta.persistence.Entity;
import jakarta.persistence.Id; import jakarta.persistence.Id;
import jakarta.persistence.OneToOne; import jakarta.persistence.ManyToOne;
import org.hibernate.envers.Audited; import org.hibernate.envers.Audited;
@ -24,7 +24,7 @@ public class BiRefIngEntity {
private String data; private String data;
@Audited @Audited
@OneToOne @ManyToOne
private BiRefEdEntity reference; private BiRefEdEntity reference;
public BiRefIngEntity() { public BiRefIngEntity() {

View File

@ -8,7 +8,7 @@ package org.hibernate.orm.test.envers.integration.onetoone.unidirectional;
import jakarta.persistence.Entity; import jakarta.persistence.Entity;
import jakarta.persistence.Id; import jakarta.persistence.Id;
import jakarta.persistence.OneToOne; import jakarta.persistence.ManyToOne;
import org.hibernate.envers.Audited; import org.hibernate.envers.Audited;
@ -26,7 +26,7 @@ public class UniRefIngEntity {
private String data; private String data;
@Audited @Audited
@OneToOne @ManyToOne
private UniRefEdEntity reference; private UniRefEdEntity reference;
public UniRefIngEntity() { public UniRefIngEntity() {