Wednesday, 22 August 2012

JPA One-To-One Relationships (Unidirectional and Bidirectional)

This post illustrates simple one-to-one relationships between two classes.

Unidirectional

@Entity
@AutoProperty
public class OneToOneUnidirectionalA implements Serializable {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private long id;

    @OneToOne
    private OneToOneUnidirectionalB b;

    private String s;

    // Setters, Getters, Constructors, Pojomatic...

}


@Entity
@AutoProperty
public class OneToOneUnidirectionalB implements Serializable {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private long id;

    // No reference to OneToOneUnidirectionalA
    // since this is a unidirectional relationship

    private String s;

    // Setters, Getters, Constructors, Pojomatic...

}
The following:
OneToOneUnidirectionalA a = new OneToOneUnidirectionalA("AAA");
OneToOneUnidirectionalB b = new OneToOneUnidirectionalB("BBB");
  
a.setB(b);
  
JPA.INSTANCE.save(b);
JPA.INSTANCE.save(a);
JPA.INSTANCE.clear();
  
OneToOneUnidirectionalA retrA
    = JPA.INSTANCE.get(OneToOneUnidirectionalA.class, a.getId());
  
System.out.println("Retrieved OneToOne Unidirectional A:");
System.out.println(retrA);
System.out.println(retrA.getB());
  
OneToOneUnidirectionalB retrB
    = JPA.INSTANCE.get(OneToOneUnidirectionalB.class, b.getId());
  
System.out.println("Retrieved OneToOne Unidirectional B:");
System.out.println(retrB);
Generates:
Retrieved OneToOne Unidirectional A:
OneToOneUnidirectionalA{id: {1}, b: {OneToOneUnidirectionalB{id: {1}, s: {BBB}}}, s: {AAA}}
OneToOneUnidirectionalB{id: {1}, s: {BBB}}
Retrieved OneToOne Unidirectional B:
OneToOneUnidirectionalB{id: {1}, s: {BBB}}

Bidirectional

A owns the relationship. We need to avoid Pojomatic circular reference issues too:
@Entity
@AutoProperty
public class OneToOneBidirectionalA implements Serializable {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private long id;

    @Property(policy=PojomaticPolicy.NONE)
    @OneToOne
    private OneToOneBidirectionalB b;

    // Setters, Getters, Constructors, Pojomatic...

}


@Entity
@AutoProperty
public class OneToOneBidirectionalB implements Serializable {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private long id;

    @Property(policy=PojomaticPolicy.NONE)
    @OneToOne(mappedBy="b")
    private OneToOneBidirectionalA a;

    // Setters, Getters, Constructors, Pojomatic...

}
The following:
OneToOneBidirectionalA a2 = new OneToOneBidirectionalA("BiAAA");
OneToOneBidirectionalB b2 = new OneToOneBidirectionalB("BiBBB");
  
JPA.INSTANCE.save(b2);
JPA.INSTANCE.save(a2);
  
a2.setB(b2);
b2.setA(a2);
  
JPA.INSTANCE.update(b2);
JPA.INSTANCE.update(a2);
JPA.INSTANCE.clear();
  
OneToOneBidirectionalA retrA2
    = JPA.INSTANCE.get(OneToOneBidirectionalA.class, a2.getId());
  
System.out.println("Retrieved OneToOne Bidirectional A:");
System.out.println(retrA2 + " -> " + retrA2.getB());
  
OneToOneBidirectionalB retrB2
    = JPA.INSTANCE.get(OneToOneBidirectionalB.class, b2.getId());
  
System.out.println("Retrieved OneToOne Bidirectional B:");
System.out.println(retrB2 + " -> " + retrB2.getA());
Generates:
Retrieved OneToOne Bidirectional A:
OneToOneBidirectionalA{id: {1}, s: {BiAAA}} -> OneToOneBidirectionalB{id: {1}, s: {BiBBB}}
Retrieved OneToOne Bidirectional B:
OneToOneBidirectionalB{id: {1}, s: {BiBBB}} -> OneToOneBidirectionalA{id: {1}, s: {BiAAA}}
The above examples are available from Github in the JPA directory. They rely on Pojomatic too. Some errors messages will be displayed because of a known and harmless issue.

1 comment:

  1. This is a typical CONSISTENCY issue as mentioned in the JPA literature. It is well discussed here.
    You can find a sample code to resolve your A class setter
    here.
    As well a sample code to resolve your B class setter here.

    ReplyDelete