(已解决,见下文)
Hibernate 4.1/Spring/JPA 项目。我正在使用 Spring 和 JPA 注释来支持事务、实体管理器注入等。
我在同一个事务中看到我的@OneToMany 延迟加载集合没有设置会话属性,当然也无法加载。如果我执行“left join fetch”来强制加载,我会得到多条指向同一个 PersistentBag 的记录——显然这会引发“shared collection”异常。
这是我的设置:
交易实体(“交易”是指金融交易)
代码:
@Entity
@Table(name = "transactionData")
@Access(AccessType.PROPERTY)
public class TransactionData extends AbstractTransaction implements java.io.Serializable {
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "id", unique = true, nullable = false)
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
@OneToMany(cascade=CascadeType.ALL,targetEntity=Location.class,fetch=FetchType.LAZY)
@JoinColumns(
{
@JoinColumn(name="routecode",referencedColumnName="v_OPERSTAT"),
@JoinColumn(name="cogrp", referencedColumnName="v_COUNTRY")
})
@Transactional
public Collection<Location> getLocations() {
return super.getLocations();
}
public void setLocations(Collection<Location> l) {
super.setLocations(l);
}
}
事务的基类:
代码:
public abstract class AbstractTransaction {
private List<Location> _locations;
@Override
@Transactional
public List<Location> getLocations() {
return _locations;
}
@Override
public void setLocations(List<Location> value) {
_locations = value;
}
}
事务实体使用 2 个整数类型列链接到位置实体,这些列在事务或位置实体上都不是 PK。
位置实体:
代码:
@Entity
@Table(name = "locations", uniqueConstraints = @UniqueConstraint(columnNames = {
"cogrp", "cugrp", "bogrp", "status", "id" }))
public class Location implements java.io.Serializable {
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "id", unique = true, nullable = false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
@Column(name = "cogrp", nullable = false)
public int getCogrp() {
return this.cogrp;
}
public void setCogrp(int cogrp) {
this.cogrp = cogrp;
}
@Column(name = "routecode")
public Integer getRoutecode() {
return this.routecode;
}
public void setRoutecode(Integer routecode) {
this.routecode = routecode;
}
}
事务实体与位置具有一对多的关系,并且大多数事务实体将指向相同的位置列表。
现在,如果我执行以下查询:
代码:
select distinct t from " + Transaction.class.getName() + " t left join fetch t.locations where " + filterSQL
我得到了结果,但几乎每个 Transaction 实体都指向相同的 PersistentBag 位置 - 不用说这会导致共享引用错误。
如果我省略 left join fetch 所有实体返回延迟加载的集合,但没有设置会话属性。
如果我进行急切加载,我只会急切加载 2 个实体,其余的仍然是惰性的(我知道这是一个内置限制,有什么方法可以覆盖它吗?)
编辑: 我开始相信这是 Hibernate 中的一个错误。如果您的查询返回指向同一个集合的多条记录(我可能会添加完全有效的场景!),那么 Hibernate 将在急切获取时重用相同的集合,并在延迟加载时将 session 设置为 null。它总是会导致对同一集合的共享引用或“无会话”错误。
我已经切换到 EclipseLink 2.4,并且在修复了我的 JPSQL 之后,它似乎在上述情况下工作正常。