1

我在两个实体之间具有以下一对一(可选)关系:

@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),但我更愿意在忽略它之前了解问题的原因。

4

1 回答 1

2

你应该使用getSession.get()而不是getSession().load()

如果 load() 在缓存或数据库中找不到对象,则会引发异常。load() 方法永远不会返回 null。如果找不到对象,get() 方法将返回 null。

load() 方法可能返回一个代理而不是一个真正的持久实例。代理是第一次访问时触发加载真实对象的占位符;我们将在本节后面讨论代理。另一方面, get() 从不返回代理。

在 get() 和 load() 之间进行选择很容易:如果您确定持久对象存在,并且不存在将被视为异常,那么 load() 是一个不错的选择。如果您不确定是否存在具有给定标识符的持久实例,请使用 get() 并测试返回值以查看它是否为空。使用 load() 有进一步的含义:应用程序可以检索到持久实例的有效引用(代理),而无需访问数据库来检索其持久状态。因此 load() 在缓存或数据库中找不到持久对象时可能不会抛出异常;当访问代理时,稍后将引发异常。

于 2013-01-23T23:32:26.540 回答