当前位置: 首页 > 面试题库 >

Hibernate使用OrphanRemoval触发约束冲突

关志
2023-03-14
问题内容

我在使用JPA / Hibernate(3.5.3)设置时遇到麻烦,在这里我有一个实体,即“ Account”类,该类具有子实体列表,“
Contact”实例。我试图能够将Contact的实例添加/删除到Account的List 属性中。

将新实例添加到集合中并调用saveOrUpdate(account)可以保留所有可爱的东西。如果我然后选择从列表中删除该联系人并再次调用saveOrUpdate,则SQL
Hibernate似乎会涉及将account_id列设置为null,这违反了数据库约束。

我究竟做错了什么?

下面的代码显然是简化的摘要,但是我认为它涵盖了问题,因为我在不同的代码中看到了相同的结果,这实际上就是这个简单的问题。

SQL:

CREATE TABLE account ( INT account_id );
CREATE TABLE contact ( INT contact_id, INT account_id REFERENCES account (account_id) );

Java:

@Entity
class Account {
  @Id
  @Column
  public Long id;

  @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
  @JoinColumn(name = "account_id")
  public List<Contact> contacts;
}

@Entity
class Contact {
  @Id
  @Column
  public Long id;

  @ManyToOne(optional = false)
  @JoinColumn(name = "account_id", nullable = false)
  public Account account;
}

Account account = new Account();
Contact contact = new Contact();

account.contacts.add(contact);
saveOrUpdate(account);

// some time later, like another servlet request....

account.contacts.remove(contact);
saveOrUpdate(account);

结果:

UPDATE contact SET account_id = null WHERE contact_id = ?

编辑#1:

可能这实际上是一个错误
http://opensource.atlassian.com/projects/hibernate/browse/HHH-5091

编辑#2:

我有一个似乎有效的解决方案,但涉及使用Hibernate API

class Account {
    @SuppressWarnings("deprecation")
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "account")
    @Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
    @JoinColumn(name = "account_id", nullable = false)
    private Set<Contact> contacts = new HashSet<Contact>();
}

class Contact {
    @ManyToOne(optional = false)
    @JoinColumn(name = "account_id", nullable = false)
    private Account account;
}

由于不推荐使用Hibernate CascadeType.DELETE_ORPHAN,因此我不得不假定它已被JPA2版本所取代,但是该实现缺少一些东西。


问题答案:

一些说明:

  • 由于您具有双向关联,因此需要添加一个mappedBy属性来声明关联的拥有方。
  • 同样不要忘记,在使用双向关联时,您需要管理链接的两端,我建议为此使用防御性方法(如下所示)。
  • 你必须实现equalshashCodeContact

因此,在中Account,像这样修改映射:

@Entity
public class Account {
    @Id @GeneratedValue
    public Long id;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "account", orphanRemoval = true)
    public List<Contact> contacts = new ArrayList<Contact>();

    public void addToContacts(Contact contact) {
        this.contacts.add(contact);
        contact.setAccount(this);
    }

    public void removeFromContacts(Contact contact) {
        this.contacts.remove(contact);
        contact.setAccount(null);
    }

    // getters, setters
}

在中Contact,重要的部分是该@ManyToOne字段应将optional标志设置为false

@Entity
public class Contact {
    @Id @GeneratedValue
    public Long id;

    @ManyToOne(optional = false)
    public Account account;

    // getters, setters, equals, hashCode

}

通过这些修改,以下内容将起作用:

Account account = new Account();
Contact contact = new Contact();

account.addToContact(contact);
em.persist(account);
em.flush();

assertNotNull(account.getId());
assertNotNull(account.getContacts().get(0).getId());
assertEquals(1, account.getContacts().size());

account.removeFromContact(contact);
em.merge(account);
em.flush();
assertEquals(0, account.getContacts().size());

和孤立的孤儿Contact被删除,按预期方式。使用Hibernate 3.5.3-Final测试。



 类似资料:
  • 问题内容: 我正在研究触发器和约束。 我有一个使用触发器的问题(说实话,我不确定如何使用触发器。) 假设我们有一个教师表。 这个教师表包含Teacher_id,ssn,first_name,last_name,class_time 例如, 和 假设学生人数上限为25(学生人数上限由老师定义,因此可以是10、22、25 …等任意数字) 一个学生想添加鲍勃的班级。但是,我想触发拒绝添加学生的触发器。(

  • 项目使用 Hibernate 3.5、Spring Webflow 2 和 Hibernate Envers 进行审计。Envers 配置为Hibernate.cfg.xml。我在实体“文章组”和“文章”之间有一对多的关系映射。表“文章”具有外键“article_group_id”引用表“article_groups”中的 id。在前端,当我删除文章时,Hibernate Envers 会为删除后

  • 我见过其他的链接错误,但没有一个能说明如何使用罐子。当我在Jboss中部署我的应用程序时,它可以正常工作,但当我将应用程序部署到websphere时,我遇到了这种链接错误。在这里可以找到一个类似的问题:调用webservice方法时出现LinkageError,但不确定如何修复它 它主要是从和加载的,带有共享类 我所拥有的是jsp调用Web服务。从消息中,我看到的唯一jars来自axis.jar,

  • 我在WebSphereApplicationServer(8.5.5.14)中遇到了LinkageError。这里也发现了类似的问题LinkageError 原因:java。lang.LinkageError:解析方法“javax/xml/soap/SOAPElement.getElementQName()Ljavax/xml/namespace/QName;”时加载约束冲突:loader“com

  • 我计划使用API中的 波姆。xml 位置检查。JAVA 位置验证器。JAVA 位置JAVA 机器人。JAVA 一个pp.java 这里的问题是,上的

  • 我的数据库中有两个表:一个用于持久化用户,另一个用于保存他们的权限。 问题是,当我尝试删除用户时,必须删除权限,这样我就可以避免收到违反约束的异常。我使用JPAcascadeType.ALL和孤儿删除=true: 问题是,只有在将要删除的用户是在另一个会话中创建的情况下,hibernate才会生成对权限的删除查询:当我创建用户时,添加一些权限,然后尝试删除它,会引发违反限制的例外情况,而在另一会话