【问题标题】:How do I update a JPA field that has "orphanRemoval=true"?如何更新具有“orphanRemoval=true”的 JPA 字段?
【发布时间】:2014-06-12 14:20:03
【问题描述】:

我正在使用 JPA 2.0 和 Hibernate 4.1.0.Final。我有这个实体(用户和地址对象之间的单向关系)......

@Entity
@Table(name = "user")
public class User implements Serializable
{

    @OneToMany(fetch = FetchType.EAGER, cascade = {CascadeType.ALL}, orphanRemoval=true)
    @JoinTable(name = "user_address", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "address_id"))
    private Set<Address> addresses;

在我的“updateUser”方法中,我有这段代码

        user.setAddresses(addresses);

哪个调用

public void setAddresses(Set<Address> addresses)
{
    if (this.addresses == null)
    {
        this.addresses = new HashSet<Address>();
    }
    this.addresses.clear();
    if (addresses != null)
    {
        this.addresses.addAll(addresses);
    }   // if
}

问题是地址只有在“地址”是新对象时才保存,而不是重新保存现有的地址实体。我需要怎么做才能使用现有地址更新我的用户?

编辑:这是我保存实体的方式...

protected Object save(Object obj)
{
    if (obj != null)
    {
        final Object id = getId(obj);
        if (id == null)
        {
            m_entityManager.persist(obj);
        }
        else
        {
            obj = m_entityManager.merge(obj);
        }   // if
    }   // if
    return obj;
} // save

【问题讨论】:

  • 而不是cascadeOneToMany 尝试使用@org.hibernate.annotations.Cascade(SAVE_UPDATE) 注释在归档addresses,如果你使用休眠。

标签: java hibernate jpa orm hibernate-mapping


【解决方案1】:

为了同时保存用户和地址,您需要调用 session.merge:

user.setAddresses(addresses);
session.merge(user);

合并将从用户级联到地址,它适用于新实体和分离实体。

同样清除列表并重新添加元素的效果也不是很好。我建议您这样做:

//always initialize the children ollections
private Set<Address> addresses = new HashSet<Address>();

//make sure equals/hashcode are implemented according to the business key semantics
//don't use the entity id for equals and hashcod

public void setAddresses(Set<Address> addresses) {  
    //1. remove the existing addresses that are not found in the new ones
    this.addresses.retainAll(addresses);
    //2. add the new addresses too, the common ones will be ignored by the Set semantics
    this.addresses.addAll(addresses);
}

【讨论】:

  • 我使用的是直接的 JPA 实现,但是当我保存我的“用户”实体时。我正在使用“entityManager.persist(user)”。这就是你在包含“session.merge”时所说的吗?
  • 是的,更新的时候需要使用entityManager.merge(user)。
  • 嗨,我已经这样做了。我编辑了我的问题以显示我用于保存的代码。
【解决方案2】:

集合属性的最佳实践是将集合初始化为一个新的空集合,让 Hibernate 代理它并以正确的方式管理对象删除。
尝试将您的代码更改为

@GenericGenerator(name = "uuid-strategy", strategy = "org.collegeboard.springboard.core.util.SpringboardUUIDGenerator")
@Entity
@Table(name = "user")
public class User implements Serializable
{

    @OneToMany(fetch = FetchType.EAGER, cascade = {CascadeType.ALL}, orphanRemoval=true)
    @JoinTable(name = "user_address", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "address_id"))
    private Set<Address> addresses = new HashSet<Address>;

另请查看 Hibernate @ManyToOne only works with CascadeType.ALL 以获取正确的注释/持久性方法对

【讨论】:

  • 你为什么使用merge()而不是persist()? merge() 创建对象的新副本,并且此对象不受管理,因此您必须对其进行 persist() 以使对象更改生效
猜你喜欢
  • 2019-08-11
  • 2011-05-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-19
  • 2012-10-22
  • 2015-06-05
  • 1970-01-01
相关资源
最近更新 更多