英文:
Hibernate EntityExistsException if trying to fetch OneToOne association lazily
问题
I have the bidirectional OneToOne association Account <-> Budget
.
根据此链接,我尝试懒加载该关联:
对于 Account.java
:
@Audited
@Entity
public class Account {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
protected long id;
@OneToOne(mappedBy = "account", cascade = CascadeType.ALL, orphanRemoval=true, fetch=FetchType.LAZY)
private Budget mainBudget;
}
...
对于 Budget.java
:
@Audited
@Entity
public class Budget {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
protected long id;
@OneToOne(fetch=FetchType.LAZY)
@MapsId
private Account account;
@OneToMany(targetEntity = Budget.class, cascade = CascadeType.ALL,
mappedBy = "parentBudget", orphanRemoval=true)
@Fetch(value = FetchMode.SUBSELECT)
private List<Budget> subBudget;
...
}
现在我正在尝试使用 DAOClass 中的 create
方法创建一个新的带有新预算的帐户,如下所示:
@Resource(name = "DBRouter", type = DatabaseRouter.class)
protected DatabaseRouter router;
@PersistenceContext
protected EntityManager em;
@Transactional
public D create(D d, boolean flush, String resource) {
router.setDataSource(resource);
if (flush) {
em.flush();
}
D obj = em.merge(d);
if (flush) {
em.flush();
}
return obj;
}
这给我带来了以下异常:
javax.persistence.EntityExistsException: 会话中已经关联了具有相同标识符值的不同对象 : [[包名].Account#50](31 行内部代码)
at org.apache.openejb.persistence.JtaEntityManager.merge(JtaEntityManager.java:203)
at [包名].DAOClass.create(DaoClass.java:75)
at [包名].DaoClass.create(DaoClass.java:66)
...
如果我删除 @MapsId
注释,那么我就不会遇到这个问题,尽管懒加载不正常工作。这个异常的原因是什么,如何解决它?
英文:
I have the bidirectional OneToOne association Account <-> Budget
.
According to this I tried to lazily load the association:
For the Account.java
:
@Audited
@Entity
public class Account {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
protected long id;
@OneToOne(mappedBy = "account", cascade = CascadeType.ALL, orphanRemoval=true, fetch=FetchType.LAZY)
private Budget mainBudget;
}
...
}
For the Budget.java
:
@Audited
@Entity
public class Budget {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
protected long id;
@OneToOne(fetch=FetchType.LAZY)
@MapsId
private Account account;
@OneToMany(targetEntity = Budget.class, cascade = CascadeType.ALL,
mappedBy = "parentBudget", orphanRemoval=true)
@Fetch(value = FetchMode.SUBSELECT)
private List<Budget> subBudget;
...
}
Now I am trying to make a new account with a new budget with the create
-method in the DAOClass looking as follows:
@Resource(name = "DBRouter", type = DatabaseRouter.class)
protected DatabaseRouter router;
@PersistenceContext
protected EntityManager em;
@Transactional
public D create(D d, boolean flush, String resource) {
router.setDataSource(resource);
if (flush) {
em.flush();
}
D obj = em.merge(d);
if (flush) {
em.flush();
}
return obj;
}
This gives me the following exception:
javax.persistence.EntityExistsException: A different object with the same identifier value was already associated with the session : [[PACKACKENAMES].Account#50](31 internal lines)
at org.apache.openejb.persistence.JtaEntityManager.merge(JtaEntityManager.java:203)
at [PACKACKENAMES].DAOClass.create(DaoClass.java:75)
at [PACKACKENAMES].DaoClass.create(DaoClass.java:66)
...
If I remove the @MapsId
annotation, then I don't have this problem, although then the lazy loading does not work properly. What is the reason for this exception and how to solve it?
答案1
得分: 1
在您的情况下,"Account" 是 "Budget" 的父实体。@MapsId 注解告诉 JPA 使用父实体的 ID 来映射带有注解的一对一关系。关联实体(行)的两个 ID 将是相同的。因此,不需要为 "Budget" 生成单独的 ID。从异常信息可以看出,即使生成了单独的 ID,也无法正常工作。
解决方案 - 从 "Budget" 实体中移除 @GeneratedValue 注解。
public class Budget {
@Id
private long id;
@OneToOne(fetch=FetchType.LAZY)
@MapsId
private Account account;
...
}
英文:
In your case Account is a parent entity for Budget. @MapsId annotation says JPA to use the id of the parent entity for the mapping of annotated one-to-one relationship. Both ids will be identical for associated entities (rows). There is no need to generate a separate id for Budget. As we can see from the exception it would even not work.
Solution - remove the @GeneratedValue annotation from the Budget entity.
public class Budget {
@Id
private long id;
@OneToOne(fetch=FetchType.LAZY)
@MapsId
private Account account;
...
}
答案2
得分: 0
你有:
public class Budget {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
protected long id;
@OneToOne(fetch=FetchType.LAZY)
@MapsId
private Account account;
但是这个映射不合理。id
不能是一个@GeneratedValue
,如果它被映射为与Account
的一对一关联。
所以:
- 移除
@GeneratedValue
注解,同时 - 确保你明确地将
id
字段设置为关联的Account
的id
字段的值。
或者,另一种选择是:
- 如果你想要一个与主键分离的外键列,就不要使用
@MapsId
。
另请参考:
这是一个类似的问题。
英文:
You have:
public class Budget {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
protected long id;
@OneToOne(fetch=FetchType.LAZY)
@MapsId
private Account account;
But this mapping doesn't make sense. The id
can't be a @GeneratedValue
if it's mapped by the one-to-one association to Account
.
So:
- remove the
@GeneratedValue
annotation, and also - make sure you explicitly set the
id
field to the value of theid
field of the associatedAccount
.
Or, alternatively:
- just don't use
@MapsId
, if what you want is a foreign key column that is separate from the primary key.
See also:
<https://stackoverflow.com/questions/76223714/hibernate-error-entityexistsexception-when-persisting-entity-with-children-mul/76226592#76226592>
Which is a similar problem.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论