HY,
我在jpa中有一个“Solve未能懒惰地初始化角色集合....例外”。我理解在会话之外,当你想要检索一个惰性集合时,如果没有会话绑定,你会得到这个错误,很好。但我不明白的是,如果我有这个弹簧控制器(代码不是100%正确,只是为了解释我的情况):
@Controller
@Autowired
EnterpriseService enterpriseService ;
public List<Enterprise> getAll(){
List<Enterprise> enterprises = enterpriseService.getAll();
for(Enterprise enterprise:enterprises){
enterprise.getEmployees();
}
return enterprises;
}
当我打电话给“enterprise.getEmployees()”时,我知道会话不再是为什么当我尝试做“enterprise.getEmployees()”时,为什么企业被视为一个jpa实体而不仅仅像普通的豆子?我的意思是;据我所知,jpa实体在会话中被视为这样,但在外部就像在这种情况下它应该被视为普通的java bean,因此对enterprise.getEmployees()的调用应该被视为调用get方法java bean,不应该抛出任何延迟异常....
也许是因为spring控制器像jpa实体那样处理企业对象而不只是像java bean一样?这种行为特定于弹簧控制器吗?
由于
答案 0 :(得分:1)
从EntityManager
返回的实体不一定是您的实体类的实例,而是扩展您的类的代理类。在许多情况下,对于此类实体的持久属性也是如此(特别是对于使用(一个/多个)To(一个/多个)注释的那些实体)。
例如,如果您使用基于字段的访问:
@Entity
public class Enterprise {
@OneToMany
private List<Employee> employees = new ArrayList<>();
public List<Employee> getEmployees() {
return employees;
}
}
这里JPA提供程序将创建一个扩展Enterprise
的代理类,并以某种方式从DB中记住以前的状态。此外,它会将employees
列表更改为自己的List
实现(不需要扩展ArrayList
)。
因为代理类可以“覆盖”您的方法,所以它可以知道您何时调用getEmployees()
并检查会话。但我不认为这会发生在这里,因为该方法没有使用任何JPA特定注释进行注释。
此外,某些框架(如Hibernate
)支持字节代码增强或字节代码检测。这会改变您的类的实现(以字节代码形式),并用一些提供者特定的代码替换对employees
的每次访问。我不知道 Spring JPA 是否提供此功能,但这可能导致检查会话。
否则,对enterprise.getEmployees()
的任何调用都应该只返回employees
的当前值 - 不对会话进行任何检查,也不使用 LazyInitializationException 。
但是调用enterprise.getEmployees().size()
会尝试初始化列表并检查会话 - 这可能会导致上述异常。
如果您使用基于属性的访问,情况会有所不同:
@Entity
public class Enterprise {
private List<Employee> employees = new ArrayList<>();
@OneToMany
public List<Employee> getEmployees() {
return employees;
}
}
此处代理类将不委托给您的实现,但会覆盖getEmployees()
方法并返回自己的List
实现,而不会更改employees
。因此,可以为enterprise.getEmployees()
获取 LazyInitalizationException 。
备注:这描述了大多数JPA实现的工作方式 - 但由于这是特定于实现的,因此一些不寻常的框架可以采取不同的方式。
答案 1 :(得分:0)
它无法做任何其他事情。唯一的选择是返回一个空的员工集合,这会更糟糕:你会错误地认为企业有0名员工,这是一个有效但完全错误的结果。
为了实现这样做会有多糟糕,让我们想象一下HospitalAnalysis实体,它拥有一系列DetectedDisease实体。并且让我们假设您尝试显示分析结果但忘记初始化集合。该页面会告诉您,您完全健康,并且您可以安全地回家,而实际上,您患有癌症,并且该程序有一个错误。我非常希望程序能够以异常崩溃并修复而不是不开始我的治疗。
尝试在没有初始化集合的情况下访问员工,因此不知道实际的员工集合,只是一个错误。通过抛出运行时异常来发出此错误信号。