Reputation: 743
I always get the exception:
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.knapp.vk.domain.Business.businessCategorySet, could not initialize proxy - no Session
I don´t want to set fetch to eager. What would be other good solutions?
Business Entity class:
@Entity
public class Business
{
@Id
@GeneratedValue
private int pk;
@ManyToMany
private Set<BusinessCategory> businessCategorySet = new HashSet<BusinessCategory>();
...
}
BusinessRepository interface:
import org.springframework.data.repository.CrudRepository;
import org.springframework.transaction.annotation.Transactional;
@Transactional
public interface BusinessRepository extends CrudRepository<Business, Integer>
{
}
Config:
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.hibernate4.HibernateExceptionTranslator;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@EnableJpaRepositories(basePackages = "com.knapp.vk.repositorynew")
@EnableTransactionManagement
public class JPAConfiguration
{
@Bean
public EntityManagerFactory entityManagerFactory() throws SQLException
{
return Persistence.createEntityManagerFactory("standardManager");
}
@Bean
public EntityManager entityManager(EntityManagerFactory entityManagerFactory)
{
return entityManagerFactory.createEntityManager();
}
@Bean
public PlatformTransactionManager transactionManager() throws SQLException
{
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory());
return txManager;
}
@Bean
public HibernateExceptionTranslator hibernateExceptionTranslator()
{
return new HibernateExceptionTranslator();
}
}
Upvotes: 2
Views: 9152
Reputation: 6759
So you can do it by initializing businessCategoruSet in Service so instead of using @Transactional
in Repository use it in Service.
Let write some method like get business by id or list of business in repository and access that method from service.
@Transactional
public Class BusinessService{
@resource
BusinessRepository businessRepository;
public Business getBusiness(){
Business business = businessRepository.getBusiness();
//Here you should initialize BusinessCategorySet
Object object = business.getBusinessCategoriesSet().size();
}
}
For more details about @Transactional
Refer this link
Upvotes: 4
Reputation: 168
Also you can add method in repository:
@Transactional(readOnly = true)
public List<Business> findAllEagerly() {
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Business> query = builder.createQuery(Business.class);
Root<Business> root = query.from(Business.class);
root.fetch(Business_.businessCategorySet);
return em.createQuery(query).getResultList();
}
or easier to use @Query in JpaRepository:
@Query("SELECT b FROM Business b JOIN FETCH b.businessCategorySet")
public List<Business> findAll();
I think good solution is to use @NamedEntityGraph
@Entity
@NamedEntityGraph(name = "Business.detail",
attributeNodes = @NamedAttributeNode("businessCategorySet"))
public class Business {...}
and in Repository
public interface BusinessRepository extends CrudRepository<Business, Integer> {
@EntityGraph(value = "Business.detail", type = EntityGraphType.LOAD)
List<Business> findAll();
}
See also:
Custom implementations for Spring Data repositories
Configuring Fetch- and LoadGraphs
Upvotes: 5
Reputation: 121
Hibernate session has its scope within transaction. So, if you are starting your transaction at service layer your hibernate session will be available till service layer. And if you are calling any object inside another object e.g. (business.getBusinessCategorySet()) which needs to be loaded lazy, will cause to throw "org.hibernate.LazyInitializationException". To resolve this issue, you have two solution 1) Load all related objects within service layer 2) Use Open Session In View (OSIV) configuration, it will make your hibernation session open till view layer.
Upvotes: 1