HHH-4982 : JPA OneToOne(optional=true) not supported with @PrimaryKeyJoinColumn

This commit is contained in:
Gail Badner 2011-10-12 01:56:56 -07:00
parent 8325933dff
commit c180d721c0
6 changed files with 464 additions and 4 deletions

View File

@ -1577,8 +1577,8 @@ public final class AnnotationBinder {
}
}
//MapsId means the columns belong to the pk => not null
//@PKJC must be constrained
final boolean mandatory = !ann.optional() || forcePersist || trueOneToOne;
//@OneToOne with @PKJC can still be optional
final boolean mandatory = !ann.optional() || forcePersist;
bindOneToOne(
getCascadeStrategy( ann.cascade(), hibernateCascade, ann.orphanRemoval(), forcePersist ),
joinColumns,

View File

@ -29,6 +29,7 @@ import org.hibernate.EmptyInterceptor;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Restrictions;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Join;
import org.hibernate.mapping.PersistentClass;
@ -36,6 +37,7 @@ import org.hibernate.mapping.Table;
import org.junit.Test;
import org.hibernate.testing.FailureExpected;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.hibernate.test.annotations.Customer;
@ -330,7 +332,7 @@ public class OneToOneTest extends BaseCoreFunctionalTestCase {
}
@Test
@TestForIssue( jiraKey = "HHH-5109" )
@FailureExpected( jiraKey = "HHH-6723" )
public void testPkOneToOneSelectStatementDoesNotGenerateExtraJoin() {
// This test uses an interceptor to verify that correct number of joins are generated.
Session s = openSession(new JoinCounter(1));
@ -354,7 +356,32 @@ public class OneToOneTest extends BaseCoreFunctionalTestCase {
assertNotNull( address );
assertNotNull( address.getOwner() );
assertEquals( address.getId(), address.getOwner().getId() );
s.flush();
s.clear();
owner = ( Owner ) s.createCriteria( Owner.class )
.add( Restrictions.idEq( owner.getId() ) )
.uniqueResult();
assertNotNull( owner );
assertNotNull( owner.getAddress() );
assertEquals( owner.getId(), owner.getAddress().getId() );
s.flush();
s.clear();
address = ( OwnerAddress ) s.createCriteria( OwnerAddress.class )
.add( Restrictions.idEq( address.getId() ) )
.uniqueResult();
address = ( OwnerAddress ) s.get( OwnerAddress.class, address.getId() );
assertNotNull( address );
assertNotNull( address.getOwner() );
assertEquals( address.getId(), address.getOwner().getId() );
s.flush();
s.clear();
tx.rollback();
s.close();
}

View File

@ -0,0 +1,138 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.test.annotations.onetoone;
import org.junit.Test;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Restrictions;
import org.hibernate.id.IdentifierGenerationException;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
/**
* @author Emmanuel Bernard
* @author Gail Badner
*/
public class OptionalOneToOneMappedByTest extends BaseCoreFunctionalTestCase {
// @OneToOne(mappedBy="address") with foreign generator
@Test
public void testBidirForeignIdGenerator() {
Session s = openSession();
Transaction tx = s.beginTransaction();
OwnerAddress address = new OwnerAddress();
address.setOwner( null );
try {
s.persist( address );
s.flush();
fail( "should have failed with IdentifierGenerationException" );
}
catch (IdentifierGenerationException ex) {
// expected
}
finally {
tx.rollback();
}
s.close();
}
@Test
public void testBidirAssignedId() throws Exception {
Session s = openSession();
s.getTransaction().begin();
PartyAffiliate affiliate = new PartyAffiliate();
affiliate.partyId = "id";
s.persist( affiliate );
s.getTransaction().commit();
s.clear();
Transaction tx = s.beginTransaction();
affiliate = ( PartyAffiliate ) s.createCriteria(PartyAffiliate.class)
.add( Restrictions.idEq( "id" ) )
.uniqueResult();
assertNotNull( affiliate );
assertEquals( "id", affiliate.partyId );
assertNull( affiliate.party );
s.clear();
affiliate = ( PartyAffiliate ) s.get( PartyAffiliate.class, "id" );
assertNull( affiliate.party );
s.delete( affiliate );
tx.commit();
s.close();
}
@Test
public void testBidirDefaultIdGenerator() throws Exception {
Session s = openSession();
s.getTransaction().begin();
PersonAddress personAddress = new PersonAddress();
personAddress.setPerson( null );
s.persist( personAddress );
s.getTransaction().commit();
s.clear();
Transaction tx = s.beginTransaction();
personAddress = ( PersonAddress ) s.createCriteria(PersonAddress.class)
.add( Restrictions.idEq( personAddress.getId() ) )
.uniqueResult();
assertNotNull( personAddress );
assertNull( personAddress.getPerson() );
s.clear();
personAddress = ( PersonAddress ) s.get( PersonAddress.class, personAddress.getId() );
assertNull( personAddress.getPerson() );
s.delete( personAddress );
tx.commit();
s.close();
}
@Override
protected Class[] getAnnotatedClasses() {
return new Class[] {
Party.class,
PartyAffiliate.class,
Owner.class,
OwnerAddress.class,
Person.class,
PersonAddress.class
};
}
}

View File

@ -0,0 +1,170 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.test.annotations.onetoone;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Restrictions;
import org.hibernate.id.IdentifierGenerationException;
import org.junit.Test;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
/**
* @author Emmanuel Bernard
* @author Gail Badner
*/
public class OptionalOneToOnePKJCTest extends BaseCoreFunctionalTestCase {
@Test
@TestForIssue( jiraKey = "HHH-4982")
public void testNullBidirForeignIdGenerator() {
Session s = openSession();
Transaction tx = s.beginTransaction();
Person person = new Person();
person.setPersonAddress( null );
try {
s.persist( person );
s.flush();
fail( "should have thrown IdentifierGenerationException.");
}
catch ( IdentifierGenerationException ex ) {
// expected
}
finally {
tx.rollback();
s.close();
}
}
@Test
@TestForIssue( jiraKey = "HHH-4982")
public void testNotFoundBidirForeignIdGenerator() {
Session s = openSession();
Transaction tx = s.beginTransaction();
Person person = new Person();
person.setPersonAddress( null );
person.setId( 1 );
try {
// Hibernate resets the ID to null before executing the foreign generator
s.persist( person );
s.flush();
fail( "should have thrown IdentifierGenerationException.");
}
catch ( IdentifierGenerationException ex ) {
// expected
}
finally {
tx.rollback();
s.close();
}
}
// @PrimaryKeyJoinColumn @OneToOne(optional=true) non-foreign generator
@Test
@TestForIssue( jiraKey = "HHH-4982")
public void testNotFoundBidirDefaultIdGenerator() {
Session s = openSession();
s.getTransaction().begin();
Owner owner = new Owner();
owner.setAddress( null );
s.persist( owner );
s.getTransaction().commit();
s.close();
s = openSession();
s.getTransaction().begin();
owner = ( Owner ) s.get( Owner.class, owner.getId() );
assertNotNull( owner );
assertNull( owner.getAddress() );
s.getTransaction().commit();
s.close();
s = openSession();
s.getTransaction().begin();
owner = ( Owner ) s.createCriteria( Owner.class )
.add( Restrictions.idEq( owner.getId() ) )
.uniqueResult();
assertNotNull( owner );
assertNull( owner.getAddress() );
s.delete( owner );
s.getTransaction().commit();
s.close();
}
@Test
public void testNotFoundBidirAssignedId() throws Exception {
Session s = openSession();
s.getTransaction().begin();
Party party = new Party();
party.partyId = "id";
party.partyAffiliate = null;
s.persist( party );
s.getTransaction().commit();
s.close();
s = openSession();
s.getTransaction().begin();
party = ( Party ) s.get( Party.class, "id" );
assertNull( party.partyAffiliate );
s.getTransaction().commit();
s.close();
s = openSession();
s.getTransaction().begin();
party = ( Party ) s.createCriteria( Party.class )
.add( Restrictions.idEq( "id" ) )
.uniqueResult();
assertNotNull( party );
assertEquals( "id", party.partyId );
assertNull( party.partyAffiliate );
s.delete( party );
s.getTransaction().commit();
s.close();
}
@Override
protected Class[] getAnnotatedClasses() {
return new Class[] {
Party.class,
PartyAffiliate.class,
Owner.class,
OwnerAddress.class,
Person.class,
PersonAddress.class
};
}
@Override
protected String[] getXmlFiles() {
return new String[] { "org/hibernate/test/annotations/onetoone/orm.xml" };
}
}

View File

@ -0,0 +1,64 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.test.annotations.onetoone;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.PrimaryKeyJoinColumn;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter;
/**
* @author Emmanuel Bernard
* @author Gail Badner
*/
@Entity
public class Person {
@Id @GeneratedValue(generator = "fk")
@GenericGenerator(strategy = "foreign", name = "fk", parameters = @Parameter(name="property", value="personAddress"))
private Integer id;
@PrimaryKeyJoinColumn
@OneToOne(optional=true)
private PersonAddress personAddress;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public PersonAddress getPersonAddress() {
return personAddress;
}
public void setPersonAddress(PersonAddress personAddress) {
this.personAddress = personAddress;
}
}

View File

@ -0,0 +1,61 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.test.annotations.onetoone;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter;
/**
* @author Gail Badner
*/
@Entity
public class PersonAddress {
@Id
@GeneratedValue
private Integer id;
@OneToOne(mappedBy="personAddress")
private Person person;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
}