Hibernate多对多级联类型问题

时间:2016-04-06 10:56:42

标签: java hibernate jpa

我目前正在项目中使用Hibernate,但我在设置多对多关系时遇到了问题。我认为我的问题与Cascade类型有关。

场景是我们有广告,每个广告可以有许多标签,但每个标签可以与许多广告相关。广告实体的ManyToMany注释是:

@ManyToMany(fetch = FetchType.LAZY, cascade = { CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH })
@JoinTable(name = "adMediaAdvertiserTag",
        joinColumns = { @JoinColumn(name = "adMediaId") },
        inverseJoinColumns = { @JoinColumn(name = "advertiserTagId") })

标签实体上的ManyToMany映射是:

@ManyToMany(mappedBy = "advertiserTags", fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST, CascadeType.MERGE })

我看到两个不同的错误,具体取决于级联类型的配置以及数据库中是否已存在标记。

如果广告中的级联类型不包含PERSIST且标签已经存在,那么我们会遇到以下异常:

TransientObjectException: object references an unsaved transient instance

如果广告上的级联类型确实包含PERSIST且标签已经存在,我们会得到:

PersistentObjectException: detached entity passed to persist

我能让这个工作的唯一方法就是没有PERSIST作为级联类型,而是循环遍历每个标记并将它们保存到会话中。

这是正确的做法吗? hibernate有没有办法自动为我处理这个问题?

如果此情况不明确或您需要更多信息,请与我们联系。

更新

我正在使用一个使用save方法的服务保存对象,该方法是springframework的CrudRepository对象。有很多代码,所以我无法真正发布所有代码。

我目前没有为我想要保存的任何对象调用任何merge或persist方法。我的印象是Hibernate会为我处理这类事情。

1 个答案:

答案 0 :(得分:1)

是否可以添加用于保存广告和标记对象的代码。我使用以下代码进行测试(我认为与您的相似)并且它可以工作:

User user = new User();
Role role = new Role();
role.setId("TEST_ROLE");
user.getRoles().add(role);

entityManager.persist(user);

User user2 = new User();
user2.getRoles().add(role);
entityManager.persist(user2);
System.out.println(user2.getId());

在用户中我有:

@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST)
@JoinTable(name = "user_roles",
        joinColumns = {@JoinColumn(name = "user_id", nullable = false, updatable = true)},
        inverseJoinColumns = {@JoinColumn(name = "role_id", nullable = false, updatable = true)})
protected List<Role> roles = new ArrayList<>();

并且在角色中我有:

@ManyToMany(mappedBy="roles")
protected List<User> users;