@ManyToOne and @OneToOne relations with @EmbeddedId

10,039

Sequencing shouldn't be used if you want a composite pk - use only the sequence generated field which is unique, or composite business fields that are unique.

Second issue is the joinColumn definitions in User. You have marked them as updatable=false, insertable=false which means the foreign keys cannot be changed through the mappings, and is why they are always null regardless of setting the relationship. Remove the updatable=false, insertable=false settings from each to have the fields set when you set the relationship.

Share:
10,039
Andreas Lenggenhager
Author by

Andreas Lenggenhager

Updated on June 04, 2022

Comments

  • Andreas Lenggenhager
    Andreas Lenggenhager almost 2 years

    I am trying to change the id of my database entities from a single long to a composite id consisting of two long's which are encapsulated in my ID.class shown below. What annotations would you use for ManyToOne and OneToMany relations? Did I made a mistake with my annotations, especially with @JoinColumns, @Embeddable and @EmbeddedId. My problem is that relations are stored with null;

    My ID class consist of an autogenerated long (pid) and a manually set secondary long (sid). This is the ID for all my entity classes:

    @Embeddable
    public class ID implements Serializable {
    
        @GeneratedValue(strategy = GenerationType.SEQUENCE)
        private long pid;
        @Column(nullable=false)
        private long sid;
    }
    

    My Entity-class (example) has a many-to-one relation to Office a one-to-one relation to Settings (both relations are uni-directional).

    @Entity
    @Table(name="user")
    public class User {
    
        @EmbeddedId
        private ID id;
    
        @ManyToOne(fetch=FetchType.LAZY)
        @JoinColumns({
            @JoinColumn(name = "office_pid", referencedColumnName = "pid", updatable=false, insertable=false),
            @JoinColumn(name = "office_sid", referencedColumnName = "sid", updatable=false, insertable=false)
        })
        private Office office;
    
        @OneToOne(cascade={CascadeType.PERSIST, CascadeType.REMOVE}, fetch=FetchType.LAZY)
        @JoinColumns({
            @JoinColumn(name = "setting_pid", referencedColumnName = "pid", updatable=false, insertable=false),
            @JoinColumn(name = "setting_sid", referencedColumnName = "sid", updatable=false, insertable=false)
        })
        private Settings setting;
    
        @OneToMany(mappedBy = "user", cascade=CascadeType.REMOVE, fetch=FetchType.LAZY)
        private List<Account> accounts= new ArrayList<>();
    }
    

    Office class (Many-To-One example):

    @Entity
    @Table(name = "office")
    public class Office {
    
        @EmbeddedId
        private ID id;
        @Column(length = 128)
        private String description;
    
    }
    

    Account class (One-To-Many example):

    @Entity
    @Table(name="account")
    public class Account {
    
        @EmbeddedId
        private ID id;
        @Column(length = 16)
        private String description;
    
        @ManyToOne(fetch=FetchType.LAZY)
        @JoinColumns({
            @JoinColumn(name = "user_pid", referencedColumnName = "pid"),
            @JoinColumn(name = "user_sid", referencedColumnName = "sid")
        })
        private User user;
    }
    

    Thanks in advance for your help.

  • Andreas Lenggenhager
    Andreas Lenggenhager over 9 years
    Thanks for your fast reply. I removed all updatable=false and insertable=false and I looks promising. But now I am stucked with the @OneToMany relations. What annotation do I need there?
  • Andreas Lenggenhager
    Andreas Lenggenhager over 9 years
    For now, I am not changing the sequencing as it works pretty well for me.
  • Chris
    Chris over 9 years
    Sorry, I'm not sure what you mean when you say you are stuck with @OneToMany relations. You were using ManyToOne and OneToOne in the code - changing the insertable, updatable flags does not mean you need to change your mappings unless you had those fields mapped through another mapping as well.
  • Andreas Lenggenhager
    Andreas Lenggenhager over 9 years
    My entites also have @OneToMany as well. I didn't mentioned it because I thought it works. But I was wrong. I updated the code in my first post with an example of an OneToMany relation.
  • Chris
    Chris over 9 years
    There is nothing wrong with the OneToMany mapping shown. My guess now is that you have a bidirectional relationship and are making the common mistake of only setting one side. When you update the Account.user, you must also add that account to the user.accounts list