0

I don't know if this is possible at all, I've been searching a lot for it but i couldn't find an answer.

Say I have two tables, Parent and Child.

I would like to map the Parent entity in such a way that it contains a reference to the Child entity, but the Child entity doesn't need to know about the Parent entity. Ideal mapping should be like this:

@Entity
public class Parent {
    
    @Id
    @SequenceGenerator(name = "parentSeq", sequenceName = "parentSeq", allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "parentSeq")
    @Column(name = "id_")
    private Long id;
    
    @OneToOne   // ??
    private Child child;
    
    // getters & setters
}

@Entity
public class Child {
    
    @Id
    private Long id;
    
    private String name;
    
    // has no back reference to the Parent entity
    // getters & setters
}

I could share the PK of the Parent table to the Child entity and make it PK and FK in the Child table if that could help, or in general i could modify the DB tables as needed in order to achieve this. Worst case scenario I can have a PK for the Child table and a FK to the Parent table. However I would not like to have a FK on the Parent table to the Child table.

The desired behavour would be:

Parent parent = new Parent();
Child child = new Child();
child.setName("childName");
parent.setChild(child);
parent.save();

So, in the case of a shared PK, the correct way to do this (AFAIK) is to first insert the Parent row, then get its Id and use it to insert a new Child row with that Id.

Is there a way to achieve this?

Hibernate version is 5.4.28 Final, JPA version 2.1

Thank you


Update:

Just to clarify, best scenario for the db structure would be like this:

Parent table:

  1. Id (Pk)
  2. Name

Child table:

  1. Id (Pk, Fk reference Parent Id)
  2. Name

Another acceptable solution however would be:

Parent table:

  1. Id (Pk)
  2. Name

Child table:

  1. Id (Pk)
  2. Name
  3. ParentId (Fk reference Parent Id)

Again, I would like to have a unidirectional mapping from Parent to Child but according to the link provided by Davide this seems impossible.

User1254
  • 85
  • 5
  • I can never understand this: if you want for `Child` to know nothing about its `Parent`, why would you want the `CHILD`'s table to have the `PARENT`'s id? – crizzis Apr 25 '21 at 17:06
  • Because I'd like to keep the foreign key in the `Child` table but I don't need a bidirectional mapping between the `Parent` and `Child` entities. If this was a `OneToMany` relationship mapping I could've use the `@JoinColumn(name="parentId")` annotation in the `Parent` entity to reference the FK in the `Child` entity. I need the same exact thing but in a `OneToOne` relationship and I don' know how to do it. – User1254 Apr 25 '21 at 21:15
  • I understand *what* you want, I just don't understand *why*. I believe the reason why `@OneToOne` creates the FK in the parent table by default is because it's more performant and flexible. Of course, I don't know your exact use case, so please take my comment with a grain of salt – crizzis Apr 26 '21 at 05:35
  • Honestly I've seen this "configuration" if you will many times, i don't think is so uncommon but i'm not an expert. From your link I found [this](http://websystique.com/hibernate/hibernate-one-to-one-unidirectional-with-shared-primary-key-annotation-example/) which is pretty much what i was looking for. Unfortunately it explicitly set the `Child`'s Id from `Parent`'s Id which is kinda ugly imo.. For now this is the closest solution to i'm looking for. Thanks for the link – User1254 Apr 26 '21 at 09:04

1 Answers1

0

Technically, you should first save Child and then Parent, but as long as they are managed by the session, Hibernate ORM will execute the operations in the right order when the transaction is committed.

I'm not sure what's the problem you are having, what you are describing is a classic unidirectional one-to-one

@Entity
public class Parent {

  ...

  @OneToOne
  @JoinColumn(name = "child_id")
  private Child child;
`
  ...
}

This mapping implies that there is a column child_id referencing a Child in the table representing a Parent.

Techincally, you need to insert first the Child, but as long as the session manages the Child and the Parent and you insert both in the same transaction, Hibernate ORM will execute the operations in the right order.

An insert will look something similar to:

        Session session = ormFactory.openSession();
        session.beginTransaction();
        Child child = new Child();
        child.setId(12);
        child.setName("Child");
        Parent parent = new Parent();
        parent.setChild(child);
        parent.setName("Parent");
        session.persist( child );
        session.persist( parent );
        session.getTransaction().commit();
        session.close();

or, you can configure the cascade option:

@Entity
public class Parent {

  ...

  @OneToOne(cascade = CascadeType.ALL)
  @JoinColumn(name = "child_id")
  private Child child;

  ...
}

and then you only have to save parent:

        Session session = ormFactory.openSession();
        session.beginTransaction();
        Child child = new Child();
        child.setId(12);
        child.setName("Child");
        Parent parent = new Parent();
        parent.setChild(child);
        parent.setName("Parent");
        session.persist( parent );
        session.getTransaction().commit();
        session.close();

You can also use the annotation @MapsId if you want Parent and Child to share the same identifier:

@Entity
public class Parent {

  @Id
  public int id;

  @OneToOne
  @MapsId
  @JoinColumn(name = "id_")
  private Child child;

  ...
}
Davide D'Alto
  • 7,421
  • 2
  • 16
  • 30
  • Right above the example 163 of the link you provided: A much more natural mapping would be the Phone were the parent-side, therefore pushing the foreign key into the PhoneDetails table. This mapping requires a bidirectional @OneToOne association which is what i needed.. I don't understand why this is not possible. In a OneToMany relationship i can put JoinCoumn(name="...") to refer to the FK in a child table but with a OneToOne relationship it seems this is not possible – User1254 Apr 24 '21 at 23:32
  • Updated question, hope it is clearer now – User1254 Apr 25 '21 at 00:12
  • Probably this is a question for the Hibernate ORM Zulip chat: developers:https://hibernate.zulipchat.com/#narrow/stream/132096-hibernate-user – Davide D'Alto Apr 25 '21 at 08:46