diff --git a/annotations/src/main/java/org/hibernate/cfg/AnnotationBinder.java b/annotations/src/main/java/org/hibernate/cfg/AnnotationBinder.java index ecf0cd3d0d..27d359c346 100644 --- a/annotations/src/main/java/org/hibernate/cfg/AnnotationBinder.java +++ b/annotations/src/main/java/org/hibernate/cfg/AnnotationBinder.java @@ -1563,7 +1563,8 @@ public final class AnnotationBinder { } } //MapsId means the columns belong to the pk => not null - final boolean mandatory = !ann.optional() || forcePersist; + //@PKJC must be constrained + final boolean mandatory = !ann.optional() || forcePersist || trueOneToOne; bindOneToOne( getCascadeStrategy( ann.cascade(), hibernateCascade, ann.orphanRemoval(), forcePersist ), joinColumns, diff --git a/annotations/src/test/java/org/hibernate/test/annotations/onetoone/OneToOneTest.java b/annotations/src/test/java/org/hibernate/test/annotations/onetoone/OneToOneTest.java index 1696b932af..c63924922c 100644 --- a/annotations/src/test/java/org/hibernate/test/annotations/onetoone/OneToOneTest.java +++ b/annotations/src/test/java/org/hibernate/test/annotations/onetoone/OneToOneTest.java @@ -3,6 +3,7 @@ package org.hibernate.test.annotations.onetoone; import java.util.Iterator; +import org.hibernate.EmptyInterceptor; import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.Transaction; @@ -174,8 +175,8 @@ public class OneToOneTest extends TestCase { party.partyId = "id"; party.partyAffiliate = affiliate; affiliate.party = party; + s.persist( party ); - s.persist( affiliate ); s.getTransaction().commit(); s.clear(); @@ -271,6 +272,41 @@ public class OneToOneTest extends TestCase { ); } + /** + * HHH-5109 @OneToOne - too many joins + * This test uses an interceptor to verify that correct number of joins + * are generated. + */ + public void testPkOneToOneSelectStatementDoesNotGenerateExtraJoin() { + + Session s = openSession(new JoinCounter(1)); + Transaction tx = s.beginTransaction(); + Owner owner = new Owner(); + OwnerAddress address = new OwnerAddress(); + owner.setAddress( address ); + address.setOwner( owner ); + s.persist( owner ); + s.flush(); + s.clear(); + + owner = ( Owner ) s.get( Owner.class, owner.getId() ); + assertNotNull( owner ); + assertNotNull( owner.getAddress() ); + assertEquals( owner.getId(), owner.getAddress().getId() ); + s.flush(); + s.clear(); + + address = ( OwnerAddress ) s.get( OwnerAddress.class, address.getId() ); + assertNotNull( address ); + assertNotNull( address.getOwner() ); + assertEquals( address.getId(), address.getOwner().getId() ); + + tx.rollback(); + s.close(); + } + + + /** * @see org.hibernate.test.annotations.TestCase#getAnnotatedClasses() */ @@ -299,3 +335,54 @@ public class OneToOneTest extends TestCase { return new String[] { "org/hibernate/test/annotations/onetoone/orm.xml" }; } } + + +/** + * Verifies that generated 'select' statement has desired number of joins + * @author Sharath Reddy + * + */ +class JoinCounter extends EmptyInterceptor { + + private static final long serialVersionUID = -3689681272273261051L; + + private int expectedNumberOfJoins = 0; + + public JoinCounter(int val) { + super(); + this.expectedNumberOfJoins = val; + } + + public String onPrepareStatement(String sql) { + + int numberOfJoins = 0; + if (sql.startsWith("select")) { + numberOfJoins = count(sql, "join"); + TestCase.assertEquals(expectedNumberOfJoins, numberOfJoins); + } + + return sql; + } + + /** + * Count the number of instances of substring within a string. + * + * @param string String to look for substring in. + * @param substring Sub-string to look for. + * @return Count of substrings in string. + */ + private int count(final String string, final String substring) + { + int count = 0; + int idx = 0; + + while ((idx = string.indexOf(substring, idx)) != -1) + { + idx++; + count++; + } + + return count; + } + +} diff --git a/annotations/src/test/java/org/hibernate/test/annotations/onetoone/OwnerAddress.java b/annotations/src/test/java/org/hibernate/test/annotations/onetoone/OwnerAddress.java index 485fa22974..807e4a30de 100644 --- a/annotations/src/test/java/org/hibernate/test/annotations/onetoone/OwnerAddress.java +++ b/annotations/src/test/java/org/hibernate/test/annotations/onetoone/OwnerAddress.java @@ -18,7 +18,7 @@ public class OwnerAddress { @GenericGenerator(strategy = "foreign", name = "fk", parameters = @Parameter(name="property", value="owner")) private Integer id; - @OneToOne(mappedBy="address", optional = false) + @OneToOne(mappedBy="address") private Owner owner; public Integer getId() { diff --git a/annotations/src/test/java/org/hibernate/test/annotations/onetoone/Party.java b/annotations/src/test/java/org/hibernate/test/annotations/onetoone/Party.java index 9c7c7e9fa6..68ad43c680 100644 --- a/annotations/src/test/java/org/hibernate/test/annotations/onetoone/Party.java +++ b/annotations/src/test/java/org/hibernate/test/annotations/onetoone/Party.java @@ -1,6 +1,7 @@ //$Id$ package org.hibernate.test.annotations.onetoone; +import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.OneToOne; @@ -14,7 +15,7 @@ public class Party { @Id String partyId; - @OneToOne + @OneToOne(cascade=CascadeType.ALL) @PrimaryKeyJoinColumn PartyAffiliate partyAffiliate; }