如何正确加载我的懒惰关联实体(不会让他们急切加载)?

时间:2013-02-08 20:27:48

标签: spring hibernate jpa lazy-loading

我正在使用Spring 3.1.1.RELEASE,Hibernate 4.1.0.Final,JPA 2.0构建一个WAR,并回复JBoss 7.1.1.Final。我有这个实体有几个懒惰的关联......

@GenericGenerator(name = "uuid-strategy", strategy = "uuid.hex")
@Entity
@Table(name = "cb_contract",
    uniqueConstraints = {@UniqueConstraint(columnNames={"OPPORTUNITY_ID","PRODUCT_ID"})}
)
public class Contract implements Serializable {

    …
    @Id
    @Column(name = "ID")
    @GeneratedValue(generator = "uuid-strategy")
    private String id;

    @OneToOne(fetch = FetchType.LAZY, targetEntity = Product.class)
    @JoinColumn(name = "PRODUCT_ID")
    @NotNull
    private Product product;

    @OneToOne(fetch = FetchType.LAZY, targetEntity = Organization.class)
    @JoinColumn(name = "ORGANIZATION_ID")
    @NotNull
    private Organization org;

我从一个交易方法加载这些实体......

@Transactional
@Service
public class ContractServiceImpl implements ContractService
...

public List<Contract> findContractByOppId(final String oppId)
{
    final Contract contract = new Contract();
    contract.setOpportunityId(oppId);
    return m_contractDao.find(contract);
}   // findContractByOppId

然后尝试将它们保存在另一个@Transactional方法中(从@Transactional公共方法调用此私有方法):

@Service
@Transactional
public class UserServiceImpl implements UserService
{
...
private void saveUserContracts(final User user, final Set<Contract> contracts)
{
    if (contracts != null)
    {
        for (final Contract contract : contracts)
        {
            contract.getOrg();
            contract.getProduct();

            final UserContract userContract = new UserContract();
            userContract.setContract(contract);
            userContract.setUser(user);
            userContractDao.save(userContract);
        }   // for
    }   // if
}   // saveUserContracts

然而,在尝试保存它们时,我得到以下例外。如何加载延迟实体(最好使用JPA而不是特定于Hibernate的方法)?

org.hibernate.LazyInitializationException: could not initialize proxy - no Session
    at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:149)
    at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:195)
    at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:185)
    at org.mainco.subco.organization.domain.Organization_$$_javassist_10.hashCode(Organization_$$_javassist_10.java)
    at org.mainco.subco.ecom.domain.Contract.hashCode(Contract.java:134)
    at java.util.HashMap.put(HashMap.java:372)
    at java.util.HashSet.add(HashSet.java:200)
    at java.util.AbstractCollection.addAll(AbstractCollection.java:305)
    at java.util.HashSet.<init>(HashSet.java:100)
    at org.mainco.subco.user.test.service.UserServiceTest.testAddUser(UserServiceTest.java:116)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

谢谢, - 戴夫

1 个答案:

答案 0 :(得分:0)

根据提供的信息,我认为至少有三件事是错的(如果我的解释与现实不符,请纠正我):

  • Contract#hashCode()似乎依赖于延迟加载的属性。不要这样做,hashCode是在每个上下文中都需要工作的基本方法,即使实体没有附加到会话中。
  • 您似乎正在做类似这样的事情:类X调用事务服务A,获取结果并将它们传递给另一个事务服务B.会发生什么是一旦A完成所有实体分离即他们不再附加到持久性会话,这意味着您不能懒惰加载成员。即使在你有会话的B区内,这些实体也不会自动重新附加。基本上这就是例外的原因。
  • UserServiceTest可能会也可能没有正确设置交易支持,实在说不出来。

您可以做的是确保X本身是事务性的,在这种情况下,A和B中的方法默认参与同一事务。在X完成之前,实体不会分离。