我在两个实体之间有以下一对一(可选)关系:
@Entity
@Table(name = "HLTH_RQRMT")
public class Requirement
{
...
@OneToOne(mappedBy = "healthRequirement", cascade = CascadeType.ALL)
private HealthRequirementSystemIdentifier requirementSystemId;
...
public HealthRequirementSystemIdentifier getRequirementSystemId()
{
return requirementSystemId;
}
}
@Entity
@Table(name = "HLTH_RQRMT_SYS_IDNTFR")
public class HealthRequirementSystemIdentifier
{
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "Hlth_Rqrmt_Id", nullable = false)
private Requirement healthRequirement;
}
从数据库加载需求后,将检查标识符:
//Load will always return a result (or exception) - works correctly.
Requirement requirement = (Requirement) getSession().load(Requirement.class, id);
//This is where the exception is thrown
if (requirement.getRequirementSystemId() == null)
当有标识符时,代码在所有环境中都能正常工作。当没有标识符时,它在单元测试和本地工作正常(通过对生产数据库进行测试确认)。 生产中没有标识符时,会抛出以下错误:
org.hibernate.ObjectNotFoundException: No row with the given identifier exists:
[Requirement#250583] at
org.hibernate.impl.SessionFactoryImpl$2.handleEntityNotFound(SessionFactoryImpl.java:419) at
org.hibernate.proxy.AbstractLazyInitializer.checkTargetState(AbstractLazyInitializer.java:154) at
org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:143) at
org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:174) at
org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190) at
Requirement_$$_javassist_66.getRequirementSystemId(Requirement_$$_javassist_66.java) at
mypackage.myclass.processResponse(MyServiceImpl.java:244)
我可以通过将属性optional=false
添加到映射注释中来触发单元测试中的上述错误。
什么可能导致单元测试和生产之间的结果不同? optional
属性的默认值为true,这就是它在单元测试中正常工作的原因。
如果我添加属性optional=true
,它对单元测试没有影响,但它是否可能在生产中解决问题?
我知道注释@NotFound(action=NotFoundAction.IGNORE)
,但我更愿意在忽略之前了解问题的原因。
答案 0 :(得分:2)
您应该使用getSession.get()
代替getSession().load()
如果load()无法在缓存或数据库中找到对象,则会出现异常 抛出。 load()方法永远不会返回null。 get()方法返回 如果无法找到该对象,则返回null。
load()方法可能返回代理而不是真正的持久性 实例。代理是占位符,触发加载 第一次访问时的真实对象;我们讨论代理 在本节后面。另一方面,get()永远不会返回 代理。
在get()和load()之间选择很简单:如果你确定持久性 对象存在,不存在将被视为异常,load()是a 不错的选择。如果您不确定是否存在给定的持久实例 标识符,使用get()并测试返回值以查看它是否为null。使用load()有 进一步暗示:应用程序可以检索到的有效引用(代理) 持久化实例,无需访问数据库即可检索其持久状态。 所以, load()在找不到持久对象时可能不会抛出异常 在缓存或数据库中;当代理时,异常将被抛出 被访问。