1

I am confused about how to save entry in db with column's join. I have @Entity bellow

@XmlRootElement
@XmlAccessorType(value = XmlAccessType.FIELD)
@Entity
@Table(name = "psc_users")
@NamedQuery(name = "User.findAll", query = "SELECT u FROM User u")
public class User implements Serializable {
    private static final long serialVersionUID = 8885916014620036457L;

    @Id
    private static final String SEQUENCE_NAME = "psc_users_user_id_seq";
    @Id
    @GeneratedValue(generator = "UseExistingOrGenerateIdGenerator",
            strategy = GenerationType.SEQUENCE)
    @GenericGenerator(name = "UseExistingOrGenerateIdGenerator",
            strategy = "com.psc.util.UseExistingOrGenerateIdGenerator",
            parameters = {
                    @org.hibernate.annotations.Parameter(name = "sequence", value = SEQUENCE_NAME)
            }
    )
    @Column(name = "USER_ID")
    private Long userId;

    @Column(name = "DEF", length = 30)
    private String def;

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "DEL_DATE")
    private Date delDate;

    @Column(name = "DISPLAY_DEF", length = 60)
    private String displayDef;

    @Column(name = "EMAIL", length = 60)
    private String email;

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "NAVI_DATE")
    private Date naviDate;

    @Column(name = "NAVI_USER")
    private String naviUser;

    @Column(name = "PHONE", length = 30)
    private String phone;

    @Column(name = "PWD", length = 40)
    private String pwd;

    //bi-directional many-to-one association to Branch
    @ManyToOne(cascade = CascadeType.MERGE)
    @JoinColumn(name = "BRNC_BRNC_ID", nullable = false)
    private Branch pscBranch;

    public Long getBrncBrncId() {
        return brncBrncId;
    }

    public void setBrncBrncId(Long brncBrncId) {
        this.brncBrncId = brncBrncId;
    }

    @Column(name = "BRNC_BRNC_ID", insertable = false, updatable = false)
    private Long brncBrncId;
    //bi-directional many-to-one association to User
    @ManyToOne(cascade = CascadeType.MERGE)
    @JoinColumn(name = "CURATOR_USER_ID")
    private User pscUser;


    public Long getCuratorUserId() {
        return curatorUserId;
    }

    public void setCuratorUserId(Long curatorUserId) {
        this.curatorUserId = curatorUserId;
    }

    @Column(name = "CURATOR_USER_ID", insertable = false, updatable = false)
    private Long curatorUserId;

    public User() {
    }

    public Long getUserId() {
        return this.userId;
    }

    public void setUserId(Long userId) {
        this.userId = userId;
    }

    public String getDef() {
        return this.def;
    }

    public void setDef(String def) {
        this.def = def;
    }

    public Date getDelDate() {
        return this.delDate;
    }

    public void setDelDate(Date delDate) {
        this.delDate = delDate;
    }

    public String getDisplayDef() {
        return this.displayDef;
    }

    public void setDisplayDef(String displayDef) {
        this.displayDef = displayDef;
    }

    public String getEmail() {
        return this.email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Date getNaviDate() {
        return this.naviDate;
    }

    public void setNaviDate(Date naviDate) {
        this.naviDate = naviDate;
    }

    public String getNaviUser() {
        return this.naviUser;
    }

    public void setNaviUser(String naviUser) {
        this.naviUser = naviUser;
    }

    public String getPhone() {
        return this.phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String getPwd() {
        return this.pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    public Branch getPscBranch() {
        return this.pscBranch;
    }

    public void setPscBranch(Branch pscBranch) {
        this.pscBranch = pscBranch;
    }

    public User getPscUser() {
        return this.pscUser;
    }

    public void setPscUser(User pscUser) {
        this.pscUser = pscUser;
    }

}

if I save User instance without field pscUser (here null) but there is valid CuratorUserId with correct value I end up in a situation with empty CuratorUserId in db. If you look at code then you will see these bound fields.

  @ManyToOne(cascade = CascadeType.MERGE)
    @JoinColumn(name = "CURATOR_USER_ID")
    private User pscUser;


    @Column(name = "CURATOR_USER_ID", insertable = false, updatable = false)
    private Long curatorUserId;

code to save user

repositoryUser.save(user);

this i see in debugger

enter image description here

this i see in database after saving my user.

enter image description here

sorry for my stupid question but I come across on a different behavior, there is code in my project which behaves in another manner. I don't want to search actual another user(curator) for saving my user, because of overhead on query

Alex
  • 3,923
  • 3
  • 25
  • 43
  • so you persist an object with a null reference and it persists null (null FK column) ... as it should. And when you retrieve the object it retrieves null (because the FK column is null in the datastore). And?! – Neil Stockton Aug 09 '16 at 09:33
  • I have practise when i didn't specify object(: only its id – Alex Aug 09 '16 at 09:54
  • If you only have an id you DO NOT have an object relationship, and JPA is designed for object relationships – Neil Stockton Aug 09 '16 at 10:43

3 Answers3

1

The @Column annotation on the curetorUserId field has properties insertable=false and updatable=false, which means that its value is ignored during inserts and updates.

You can either change these properties to true (but it can break your application in some other places) or just fill in pscUser field using EntityManager.getReference, which just creates a proxy and doesn't actualy produce a query to the database.

mateuszlo
  • 1,309
  • 1
  • 11
  • 10
  • thanks for answer but i haven't understood why it want have reference on the object? Because of inseatable=false and updatable=false?? – Alex Aug 09 '16 at 09:30
  • what will be if i specify not valid pscUser( which isn't consisted in db, but his id is consisted in db? In my mind it won't entail any bad effects, with this attributies – Alex Aug 09 '16 at 09:36
  • You have 2 fields in User class, that are connected to the same column in the database: pscUser and curatorUserId. During fetching data from database both fields are filled in by hibernate. But because of insertable=false and updatable=false during inserts only pscUser is used, and curatorUserId is ignored. – mateuszlo Aug 09 '16 at 09:39
  • with answer Alan Hay i can conclude that i should always specify object or my field will be null in db? inseartable and updatable only for excluding side effects on db. – Alex Aug 09 '16 at 10:04
1

Your mapping should look like the below:

@XmlRootElement
@XmlAccessorType(value = XmlAccessType.FIELD)
@Entity
@Table(name = "psc_users")
@NamedQuery(name = "User.findAll", query = "SELECT u FROM User u")
public class User implements Serializable {
    private static final long serialVersionUID = 8885916014620036457L;

    @Id
    private static final String SEQUENCE_NAME = "psc_users_user_id_seq";
    @Id
    @GeneratedValue(generator = "UseExistingOrGenerateIdGenerator",
            strategy = GenerationType.SEQUENCE)
    @GenericGenerator(name = "UseExistingOrGenerateIdGenerator",
            strategy = "com.psc.util.UseExistingOrGenerateIdGenerator",
            parameters = {
                    @org.hibernate.annotations.Parameter(name = "sequence", value = SEQUENCE_NAME)
            }
    )
    @Column(name = "USER_ID")
    private Long userId;

    @Column(name = "DEF", length = 30)
    private String def;

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "DEL_DATE")
    private Date delDate;

    @Column(name = "DISPLAY_DEF", length = 60)
    private String displayDef;

    @Column(name = "EMAIL", length = 60)
    private String email;

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "NAVI_DATE")
    private Date naviDate;

    @Column(name = "NAVI_USER")
    private String naviUser;

    @Column(name = "PHONE", length = 30)
    private String phone;

    @Column(name = "PWD", length = 40)
    private String pwd;

    //bi-directional many-to-one association to Branch
    @ManyToOne(cascade = CascadeType.MERGE)
    @JoinColumn(name = "BRNC_BRNC_ID", nullable = false)
    private Branch pscBranch;

    //bi-directional many-to-one association to User
    @ManyToOne(cascade = CascadeType.MERGE)
    @JoinColumn(name = "CURATOR_USER_ID")
    private User pscUser;

    public User() {

    }
}

You need to think in terms of objects. The FK will only be set in the database if you set the pscUser reference to an instance of a User. If this is an existing User then you need to set a reference to the existing persistent entity.

Alan Hay
  • 22,665
  • 4
  • 56
  • 110
  • but there is an another behavior when enough to set curatorUserId. But pscUser is null. – Alex Aug 09 '16 at 09:41
  • No because it is set to updateable/insertable false. Youi are using an ORM so think in terms of objects. – Alan Hay Aug 09 '16 at 09:42
  • Okey, if i think in terms of objects and remove inseartable=false and updateable=false. Will it keep its behavior? If i only specify CuratorUserId and pscUser=null – Alex Aug 09 '16 at 09:52
  • No I think it will complain about duplicate columns but try it. – Alan Hay Aug 09 '16 at 09:58
0

Real answer is that I have two points for saving and updating my entity. Please see this Hibernate: Where do insertable = false, updatable = false belong in composite primary key constellations involving foreign keys?

Alex
  • 3,923
  • 3
  • 25
  • 43