【问题标题】:Hibernate: OneToMany save children by cascadeHibernate:OneToMany 通过级联保存孩子
【发布时间】:2012-03-27 20:55:18
【问题描述】:

在 Parent 类中有一个列表 List。保存父级时,已添加或更改的子级应由休眠保存/更新。

我找到了很多关于这个的解释,但是,我就是不明白。

Parent.class 尝试A

@Entity
public class Parent {
// id and other attributes
@OneToMany(mappedBy = "parent")
@org.hibernate.annotations.Cascade(org.hibernate.annotations.CascadeType.ALL)
protected List<child> children;

Parent.class 尝试 B

@Entity
public class Parent {
// id and other attributes
  @OneToMany(mappedBy = "parent", cascade = { javax.persistence.CascadeType.ALL },
 orphanRemoval = true)
 @org.hibernate.annotations.Cascade({ 
 org.hibernate.annotations.CascadeType.PERSIST,
 org.hibernate.annotations.CascadeType.MERGE,
 org.hibernate.annotations.CascadeType.REFRESH,
 org.hibernate.annotations.CascadeType.SAVE_UPDATE,
 org.hibernate.annotations.CascadeType.REPLICATE,
 org.hibernate.annotations.CascadeType.LOCK,
 org.hibernate.annotations.CascadeType.DETACH })
protected List<child> children;

子代被添加到新的父代。之后两者都被保存了

sessionFactory.getCurrentSession().saveOrUpdate(parent);

但是,在刷新时,我收到以下错误:

org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: de.pockettaxi.backend.model.ride.RideSingle
at org.hibernate.engine.ForeignKeys.getEntityIdentifierIfNotUnsaved(ForeignKeys.java:243)
at org.hibernate.type.EntityType.getIdentifier(EntityType.java:456)
at org.hibernate.type.ManyToOneType.isDirty(ManyToOneType.java:265)
at org.hibernate.type.ManyToOneType.isDirty(ManyToOneType.java:275)
at org.hibernate.type.TypeHelper.findDirty(TypeHelper.java:295)
at org.hibernate.persister.entity.AbstractEntityPersister.findDirty(AbstractEntityPersister.java:3378)
at org.hibernate.event.def.DefaultFlushEntityEventListener.dirtyCheck(DefaultFlushEntityEventListener.java:520)
at org.hibernate.event.def.DefaultFlushEntityEventListener.isUpdateNecessary(DefaultFlushEntityEventListener.java:230)
at org.hibernate.event.def.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:154)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:219)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:99)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216)

有人看到我的错误吗?

非常感谢!!

【问题讨论】:

  • 在保存之前发布 child 的代码以及构建对象的方式。

标签: hibernate one-to-many cascade hibernate-annotations


【解决方案1】:

我猜如果你回答第一条评论中的问题,我们会遇到这种情况:

  • 你有一个已经持久化的父级
  • 您有尚未持久化的新子对象
  • 您将子项添加到父项并执行 saveOrUpdate

在这种情况下,hibernate 只是将保存或更新级联到子级,但它们无法保存或更新,因为它们还没有持久化。现在 Hibernate 简单地说“我无法更新非持久实体”

一句话:Hibernate只把它发出来的东西级联。在这种情况下,您发出一个 "SAVE_UPDATE",它被级联然后进一步传递给孩子。我猜你希望 Hibernate 很聪明,并且会为这里的孩子们坚持下去。但这不是 Hibernate 在这里的工作方式,我之前也遇到过类似的情况。有点混乱,但如果你曾经了解级联是如何工作的,你就会看到这种情况。

【讨论】:

    【解决方案2】:

    您的 Parent.class 尝试 A 似乎已经正确。但是要在保存父级的同时级联子级,则必须将级联放在所有者侧(在一对多中,它是具有外键的实体)。

    试试这个

    @Entity
    public class Parent {
        @OneToMany(mappedBy = "parent")
        protected List<Child> children;
    }
    

    在你的 Child.class 中

    @Entity
    public class Child {
        @ManyToOne
        @Cascade(value={org.hibernate.annotations.CascadeType.ALL})
        @JoinColumn(name="PARENT_ID")
        protected Parent parent;
    }
    

    【讨论】:

    • 这样有效吗?对我来说,当 Parent 还没有坚持时 - 它不起作用!因此,真正的解决方案看起来:在事务中 - 保存父级,通过链接父级保存子级
    【解决方案3】:

    试试这个:

    @Entity
    @Table(name = "TABLE_PARENT")
    public class Parent{
        @OneToMany(mappedBy="parent", cascade=CascadeType.PERSIST)
        private List<Child> children;
    }
    
    @Entity
    @Table(name = "TABLE_CHILD")
    public class Child{
        @ManyToOne(fetch=FetchType.LAZY)
        @JoinColumn(name="PARENT_ID")
        private Parent parent;
    }
    

    用法

    public void save(){
      Parent parent = new Parent();
      List<Child> children = new ArrayList<>();
      Child child = new Child();
      child.setParent(parent);
      children.add(child);
      parent.setChildren(children);
    
      parentRepository.save(parent);
    }
    

    注意:不要忘记在子对象上设置父对象,否则你会得到 TABLE_CHILD.PARENT_ID null/empty

    【讨论】:

      【解决方案4】:

      我需要一种将实体与新加入的(子)实体一起插入的方法。一种方法是分开操作(例如,先保存连接的实体,然后再保存主实体)。 但是,Hibernate 支持插入带有新连接实体的新实体。 看一个例子:How to insert OneToMany children by cascade

      【讨论】:

        【解决方案5】:

        这只是一种方法,经过多次实验(保存子实体并自动创建关系),它按预期工作。我希望它会有所帮助。

        @Entity
        public class Parent {
            @Id
            private Long id;
        
            @JoinColumn(name = "parentId")
            @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
            private Set<Child> children;
        }
        
        @Entity
        public class Child {
            @Id
            private Long id;
            private Long parentId;
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-06-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-01-16
          相关资源
          最近更新 更多