Hibernate代理对象上没有会话错误

时间:2014-09-16 02:47:33

标签: hibernate spring-mvc jpa spring-orm

我正在努力编辑和更新嵌套对象,因为我一再打击这个Hibernate Lazy Loading错误。

在我的申请中:

  1. 我将图像集绑定到产品。
  2. 我使用格式化程序转换图像集以便在选择框中使用,因此用户可以选择图像集。
  3. 如果表单成功,对象绑定并且关系正确保存,则效果很好。
  4. 但是如果验证失败,只要UI层尝试访问嵌套对象值,我就会得到可怕的Lazy Initialization / No Session错误!
  5. 所以我尝试编写一个方法来初始化相关对象作为一种解决方法:

    @Transactional
    public void initObject(Variant variant) {
        Hibernate.initialize(variant.getOption1());
        Hibernate.initialize(variant.getOption2());
        Hibernate.initialize(variant.getOption3());
        Hibernate.initialize(variant.getImageSet());
    }
    

    该方法的前3行(这些是单向一对一),但第四行不是(这是多对一),它仍然没有代理。

    我也试过制作Eager fetch类型的所有东西。

    这些都没有奏效。

    问题可能是我正在创建父对象,当有验证错误时它不会保存到数据库中,但嵌套对象无论出于何种原因都是懒惰的代理对象,无论获取类型如何(请参阅下面的格式化程序。)

    我该如何解决这个问题?

    这是格式化程序组件:

    @Component
    public class ImageSetFormatter implements Formatter<ProductImageSet> {
    
        private static Logger logger = LogManager.getLogger(VariantController.class.getName());
    
        @Autowired
        private ProductImageService imageService;
    
        @Override
        public ProductImageSet parse(String s, Locale locale) throws ParseException {
            logger.entry();
    
            Long imageSetId = Long.valueOf(s);
            logger.exit();
            return imageService.getImageSet(imageSetId);
        }
    
        @Override
        public String print(ProductImageSet productImageSet, Locale locale) {
            logger.entry();
    
            logger.exit();
            return Long.toString(productImageSet.getId());
        }
    }
    

    当线路Hibernate.initialize(variant.getImageSet())时的Stacktrace 被称为:

      

    org.springframework.web.util.NestedServletException:Request   处理失败;嵌套异常是   org.hibernate.LazyInitializationException:无法初始化代理    - 没有Session org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:973)     org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:863)     javax.servlet.http.HttpServlet.service(HttpServlet.java:644)     org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)     javax.servlet.http.HttpServlet.service(HttpServlet.java:725)     org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)     org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)     org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)     org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)     org.springframework.security.web.FilterChainProxy $ VirtualFilterChain.doFilter(FilterChainProxy.java:330)     org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)     org.springframework.security.web.FilterChainProxy $ VirtualFilterChain.doFilter(FilterChainProxy.java:342)     org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)     org.springframework.security.web.FilterChainProxy $ VirtualFilterChain.doFilter(FilterChainProxy.java:342)     org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)

    相关对象关系:

       @Entity
    @Table(name="variants")
    @EntityListeners({AuditingEntityListener.class})
    public class Variant extends AbstractAuditable<Customer, Long> {
    
        @OneToOne
        private VariantOptionValue option1;
    
        @OneToOne
        private VariantOptionValue option2;
    
        @OneToOne
        private VariantOptionValue option3;
    
        ...
    
         @ManyToOne
        @JoinColumn(name="image_set_id")
        @LazyCollection(LazyCollectionOption.FALSE )
        private ProductImageSet imageSet;
    
    
    
    }
    
    
    @Entity
    @Table(name="product_image_set")
    @EntityListeners({AuditingEntityListener.class})
    public class ProductImageSet extends AbstractAuditable<Customer, Long> {
    
    
        public ProductImageSet(String label)
        {
            this.label = label;
        }
    
        public ProductImageSet(){
    
        }
    
        @Basic
        @Column(length = 50, nullable = false)
        private String label;
    
        @OneToMany(mappedBy = "imageSet", fetch = FetchType.EAGER)
        private List<ProductImage> images;
    
        @OneToMany(mappedBy = "imageSet", fetch = FetchType.EAGER)
        private List<Variant> variants;
    
        private int sequence;
    
        @ManyToOne
        @JoinColumn(name = "product_id")
        private Product product;
    
        ...
    }
    

1 个答案:

答案 0 :(得分:0)

您可能想尝试两件事。

1-添加OpenEntityManagerInViewFilter

<filter>
    <filter-name>openEntityManagerInViewFilter</filter-name>
    <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
    <init-param>
        <param-name>entityManagerFactoryBeanName</param-name>
        <param-value>entityManagerFactory</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>openEntityManagerInViewFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

2-将您的实体/表单/模型添加到会话

@Controller
@SessionAttributes("yourEntityFormModel")
public class YourController {
    ...
}

---------更新

发生的事情是,在一个在一个事务中运行的注释方法中,Hibernate将能够根据需要从该实体中检索关系。

所以,下面的例子工作正常。

@Transactional
public void updateEmployeesFromDepartment(int depId) {

    Department dep = departmentRepository.findOne(dep.getId());
    for (Employee e : dep.getEmployees()) {
        // update whatever you want
    }

}

但我不希望这种情况发挥作用......

public void updateEmployeesFromDepartment(int depId) {

    Department dep = departmentRepository.findOne(dep.getId());
    for (Employee e : dep.getEmployees()) {
        // update whatever you want
    }

}