title: Hibernate 4 + Spring Data CrudRepository, CLI application: failed to lazily initialize a collection: could not initialize proxy - no Session
body: <p>I am trying to run Spring-based CLI application which uses Spring Data CrudRepository to access Hibernate4-based persistence layer implemented using JPA annotations over MySQL5 (InnoDB) database using c3p0 connection pool.</p>
  
  <p>I receive the following exception:</p>
  
  <pre><code>Exception in thread "main" java.lang.RuntimeException: org.springframework.orm.hibernate3.HibernateSystemException: failed to lazily initialize a collection of role: &lt;package&gt;.entity.User.categories, could not initialize proxy - no Session; nested exception is org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: &lt;package&gt;.entity.User.categories, could not initialize proxy - no Session
  </code></pre>
  
  <p>I'm newbie with Spring Data and Hibernate. From my point of view it's an issue with two different transactions (one in <code>UserServiceImpl::findByLogin</code> and another in <code>CategoryServiceImpl::deleteByUser</code>). Changing <code>User</code> entity to use Eager fetch type for Categories helps, but I want to use lazy loading in this method.</p>
  
  <p>Can I still use lazy fetch type in <code>UserServiceImpl::findByLogin</code> and fetch dependent objects in service consumer later with <code>CrudRepository</code> and Spring-managed transactions in Service Layer?</p>
  
  <p>Excerpt from the application which causes an exception:</p>
  
  <pre><code>    User user = userService.findByLogin(login);
      categoryService.deleteByUser(user);
  </code></pre>
  
  <hr>
  
  <p>EDIT: I tried to use <code>EntityManager::merge</code>, but with no luck:</p>
  
  <pre><code>@Service
  @Repository
  @Transactional
  public class CategoryServiceImpl implements CategoryService, InitializingBean {
  
      @Autowired
      private CategoryRepository repository;
  
      @Autowired
      private EntityManagerFactory entityManagerFactory;
  
      private EntityManager entityManager;
  
      @Override
      public void afterPropertiesSet() throws Exception {
          entityManager = entityManagerFactory.createEntityManager();
      }
  
      @Override
      @Transactional(readOnly = true)
      public Category findById(Long categoryId) {
          return repository.findOne(categoryId);
      }
  
      @Override
      @Transactional
      public Category save(Category category) {
          return repository.save(category);
      }
  
      @Override
      @Transactional
      public void delete(Category category) {
          repository.delete(category);
      }
  
      @Override
      @Transactional
      public void deleteByUser(User user) {
          entityManager.merge(user);
          repository.delete(user.getCategories());
      }
  }
  </code></pre>
  
  <hr>
  
  <p>Services (injected with <code>@Autowired</code>):
  User service:</p>
  
  <pre><code>package &lt;package&gt;.service.jpa;
  
  import com.google.common.collect.Lists;
  import &lt;package&gt;.entity.User;
  import &lt;package&gt;.repository.UserRepository;
  import &lt;package&gt;.service.UserService;
  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.stereotype.Repository;
  import org.springframework.stereotype.Service;
  import org.springframework.transaction.annotation.Transactional;
  
  import java.util.List;
  
  @Service
  @Repository
  @Transactional
  public class UserServiceImpl implements UserService {
  
      @Autowired
      private UserRepository repository;
  
      @Override
      @Transactional(readOnly = true)
      public List&lt;User&gt; findAll() {
          return Lists.newArrayList(repository.findAll());
      }
  
      @Override
      @Transactional(readOnly = true)
      public User findById(Long userId) {
          return repository.findOne(userId);
      }
  
      @Override
      @Transactional(readOnly = true)
      public User findByLogin(String login) {
          return repository.findByLogin(login);
      }
  
      @Override
      @Transactional
      public User save(User user) {
          return repository.save(user);
      }
  
      @Override
      @Transactional
      public void delete(User user) {
          repository.delete(user);
      }
  }
  </code></pre>
  
  <p>Category service:</p>
  
  <pre><code>package &lt;package&gt;.service.jpa;
  
  import &lt;package&gt;.entity.Category;
  import &lt;package&gt;.entity.User;
  import &lt;package&gt;.repository.CategoryRepository;
  import &lt;package&gt;.service.CategoryService;
  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.stereotype.Repository;
  import org.springframework.stereotype.Service;
  import org.springframework.transaction.annotation.Transactional;
  
  @Service
  @Repository
  @Transactional
  public class CategoryServiceImpl implements CategoryService {
  
      @Autowired
      private CategoryRepository repository;
  
      @Override
      @Transactional(readOnly = true)
      public Category findById(Long categoryId) {
          return repository.findOne(categoryId);
      }
  
      @Override
      @Transactional
      public Category save(Category category) {
          return repository.save(category);
      }
  
      @Override
      @Transactional
      public void delete(Category category) {
          repository.delete(category);
      }
  
      @Override
      @Transactional
      public void deleteByUser(User user) {
          repository.delete(user.getCategories());
      }
  }
  </code></pre>
  
  <p>Entities:
  User:</p>
  
  <pre><code>package &lt;package&gt;.entity;
  
  import javax.persistence.*;
  import java.util.HashSet;
  import java.util.Set;
  
  @Entity
  @Table
  public class User {
      private Long userId;
      private int version;
      private String login;
      private Set&lt;Category&gt; categories = new HashSet&lt;Category&gt;();
      private Set&lt;CategoryFeed&gt; categoryFeeds = new HashSet&lt;CategoryFeed&gt;();
  
      @Id
      @GeneratedValue
      public Long getUserId() {
          return userId;
      }
  
      public void setUserId(Long userId) {
          this.userId = userId;
      }
  
      @Version
      public int getVersion() {
          return version;
      }
  
      public void setVersion(int version) {
          this.version = version;
      }
  
      @Column
      public String getLogin() {
          return login;
      }
  
      public void setLogin(String login) {
          this.login = login;
      }
  
      @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
      public Set&lt;Category&gt; getCategories() {
          return categories;
      }
  
      public void setCategories(Set&lt;Category&gt; categories) {
          this.categories = categories;
      }
  
      public void addCategory(Category category) {
          categories.add(category);
      }
  
      @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
      public Set&lt;CategoryFeed&gt; getCategoryFeeds() {
          return categoryFeeds;
      }
  
      public void setCategoryFeeds(Set&lt;CategoryFeed&gt; categoryFeeds) {
          this.categoryFeeds = categoryFeeds;
      }
  
      @Override
      public boolean equals(Object o) {
          if (this == o) {
              return true;
          }
          if (!(o instanceof User)) {
              return false;
          }
  
          User user = (User) o;
  
          if (login != null ? !login.equals(user.login) : user.login != null) {
              return false;
          }
  
          return true;
      }
  
      @Override
      public int hashCode() {
          return login != null ? login.hashCode() : 0;
      }
  }
  </code></pre>
  
  <p>Category:</p>
  
  <pre><code>package &lt;package&gt;.entity;
  
  import javax.persistence.*;
  import java.util.HashSet;
  import java.util.Set;
  
  @Entity
  @Table(uniqueConstraints = @UniqueConstraint(columnNames = {"userId", "title"}))
  public class Category {
      public static final String ROOT_CATEGORY_TITLE = "";
  
      private Long categoryId;
      private int version;
      private User user;
      private String title = ROOT_CATEGORY_TITLE;
  
      private Set&lt;CategoryFeed&gt; feeds = new HashSet&lt;CategoryFeed&gt;();
  
      @Id
      @GeneratedValue
      public Long getCategoryId() {
          return categoryId;
      }
  
      public void setCategoryId(Long categoryId) {
          this.categoryId = categoryId;
      }
  
      @Version
      public int getVersion() {
          return version;
      }
  
      public void setVersion(int version) {
          this.version = version;
      }
  
      @ManyToOne
      @JoinColumn(name = "userId")
      public User getUser() {
          return user;
      }
  
      public void setUser(User user) {
          this.user = user;
      }
  
      @Column(name = "title")
      public String getTitle() {
          return title;
      }
  
      public void setTitle(String title) {
          this.title = title;
      }
  
      @ManyToMany(mappedBy = "categories", cascade = CascadeType.ALL)
      public Set&lt;CategoryFeed&gt; getFeeds() {
          return feeds;
      }
  
      public void setFeeds(Set&lt;CategoryFeed&gt; feeds) {
          this.feeds = feeds;
      }
  
      public void addFeed(CategoryFeed feed) {
          this.feeds.add(feed);
      }
  
      @Override
      public boolean equals(Object o) {
  
          if (this == o) {
              return true;
          }
          if (!(o instanceof Category)) {
              return false;
          }
  
          Category category = (Category) o;
  
          if (title != null ? !title.equals(category.title) : category.title != null) {
              return false;
          }
          if (user != null ? !user.equals(category.user) : category.user != null) {
              return false;
          }
  
          return true;
      }
  
      @Override
      public int hashCode() {
          int result = user != null ? user.hashCode() : 0;
          result = 31 * result + (title != null ? title.hashCode() : 0);
          return result;
      }
  }
  </code></pre>