Foreign key not stored in child entity (one-to-man

2019-02-12 09:00发布

I'm quite new to hibernate and have stumbled on this problem, which I can't find solution for.

When persisting parent object (with one-to-many relationship with child), the foreign-key to this parent is not stored in child's table.

My classes:

Parent.java

@javax.persistence.Table(name = "PARENT")
@Entity
public class PARENT {
  private Integer id;

  @javax.persistence.Column(name = "ID")
  @Id
  @GeneratedValue(strategy=GenerationType.AUTO)
  public Integer getId() {
    return id;
  }

  public void setId(Integer id) {
    this.id = id;
  }

  private Collection<Child> children;

  @OneToMany(mappedBy = "parent", fetch = FetchType.EAGER, cascade = {CascadeType.ALL})
  @Cascade({org.hibernate.annotations.CascadeType.ALL})
  public Collection<Child> getChildren() {
    return children;
  }

  public void setChildren(Collection<Child> children) {
    this.children = children;
  }
}

Child.java

@javax.persistence.Table(name = "CHILD")
@Entity
@IdClass(Child.ChildId.class)
public class Child {
  private String childId1;

  @Id
  public String getChildId1() {
    return childId1;
  }

  public void setChildId1(String childId1) {
    this.childId1 = childId1;
  }

  private String childId2;

  @Id
  public String getChildId2() {
    return childId2;
  }

  public void setChildId2(String childId2) {
    this.childId2 = childId2;
  }

  private Parent parent;

  @ManyToOne
  @javax.persistence.JoinColumn(name = "PARENT_ID", referencedColumnName = "ID")
  public Parent getParent() {
    return parent;
  }

  public void setParent(Operation parent) {
    this.parent = parent;
  }

  public static class ChildId implements Serializable {
    private String childId1;

    @javax.persistence.Column(name = "CHILD_ID1")
    public String getChildId1() {
      return childId1;
    }

    public void setChildId1(String childId1) {
      this.childId1 = childId1;
    }

    private String childId2;

    @javax.persistence.Column(name = "CHIILD_ID2")
    public String getChildId2() {
      return childId2;
    }

    public void setChildId2(String childId2) {
      this.childId2 = childId2;
    }

    public ChildId() {
    }

    @Override
    public boolean equals(Object o) {
      if (this == o) return true;
      if (o == null || getClass() != o.getClass()) return false;

      ChildId that = (ChildId) o;

      if (childId1 != null ? !childId1.equals(that.childId1) : that.childId1 != null) 
        return false;
      if (childId2 != null ? !childId2.equals(that.childId2) : that.childId2 != null)
        return false;

      return true;
    }

    @Override
    public int hashCode() {
      int result = childId1 != null ? childId1.hashCode() : 0;  
      result = 31 * result + (childId2 != null ? childId2.hashCode() : 0);
      return result;
    }
  }
}

Test.java

public class Test() {

  private ParentDao parentDao;

  public void setParentDao(ParentDao parentDao) {
    this.parentDao = parentDao;
  }

  private ChildDao childDao;

  public void setChildDao(ChildDao childDao) {
    this.childDao = parentDao;
  }

  test1() {
    Parent parent = new Parent();

    Child child = new Child();
    child.setChildId1("a");
    child.setChildId2("b");
    ArrayList<Child> children = new ArrayList<Child>();
    children.add(child);

    parent.setChildren(children);
    parent.setValue("value");

    parentDao.save(parent); //calls hibernate's currentSession.saveOrUpdate(entity)
  }

  test2() {
    Parent parent = new Parent();
    parent.setValue("value");
    parentDao.save(parent); //calls hibernate's currentSession.saveOrUpdate(entity)

    Child child = new Child();
    child.setChildId1("a");
    child.setChildId2("b");
    child.setParent(parent);
    childDao.save(); //calls hibernate's currentSession.saveOrUpdate(entity)
  }
}

When calling test1(), both entities get written to database, but field PARENT_ID in CHILD table stays empty.

The only workaround I have so far is test2() - persisting parent first, and then the child.

My goal is to persist parent and its children in one call to save() on Parent. Any ideas?

5条回答
叛逆
2楼-- · 2019-02-12 09:08

The problem is, in test1(), you are saving the child before you save the parent. In test2(), you are saving the parent first, then the child, which is correct, and is why it is working.

Think about it this way. Can you be born before your mother and father are born? No, they must exist before you can exist. Crate the parent, then the child, as you do in test2().

If you want, you can edit you parentDAO.save() to save or update any referenced children. That way, they save with 1 call.

查看更多
叼着烟拽天下
3楼-- · 2019-02-12 09:11

You can also add an extra method to your parent like

public void addChild(Child child) 

which does something like

    child.setParent(this);
查看更多
你好瞎i
4楼-- · 2019-02-12 09:21

I have a good solution for that case:D

mappedBy means inverse = "true" . so you must inverse = "false"

try it..

@OneToMany(fetch = FetchType.EAGER, cascade ={CascadeType.ALL})//javax.persistent.CascadeType
@JoinColumn(name = "parent_id")//parent's foreign key
public Collection<Child> getChildren() {
    return children;
}

I hope it s good to be work

查看更多
叼着烟拽天下
5楼-- · 2019-02-12 09:27

Before you save the parent, it hasn't been assigned an ID. So, when you save the child first, it has no foreign key to save. You want to do it like test2(), but wrap in in a transaction. Take a look here. I think the section titled "Transaction demarcation with EJB/CMT" may be what you want.

查看更多
放我归山
6楼-- · 2019-02-12 09:28

Main problem in test1() is that you are not setting parent in child object. you should say.. child.setParent(parent). just setting child in parent doesn't mean that child is aware of parent. in fact, its child which owns relationship. so, its necessary to set parent in the child object. sequence of saveorUpdate() call on parent or child is immaterial.

test2() is working because you have set parent in child object by calling child.setParent(). THis is missing in test1().

查看更多
登录 后发表回答