Hibernate 4 + Ressort des Données CrudRepository, CLI application: échec paresseusement initialiser une collection: impossible d'initialiser le proxy - pas de Session

Je suis en train de lancer de Printemps à base de CLI application qui utilise les Données du Printemps CrudRepository pour accéder à Hibernate4 base de la couche de persistance mis en œuvre en utilisant les annotations JPA sur MySQL5 (InnoDB) de la base de données à l'aide de c3p0 pool de connexion.

Je reçois l'exception suivante:

Exception in thread "main" java.lang.RuntimeException: org.springframework.orm.hibernate3.HibernateSystemException: failed to lazily initialize a collection of role: <package>.entity.User.categories, could not initialize proxy - no Session; nested exception is org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: <package>.entity.User.categories, could not initialize proxy - no Session

Je suis novice avec le Printemps des Données et de la mise en veille prolongée. De mon point de vue c'est un problème avec deux opérations distinctes (l'une dans UserServiceImpl::findByLogin et un autre dans CategoryServiceImpl::deleteByUser). Changer User entité à utiliser Désireux type d'extraction pour les Catégories aide, mais je veux utiliser le chargement paresseux dans cette méthode.

Puis-je encore utiliser paresseux type d'extraction dans UserServiceImpl::findByLogin et récupérer les objets dépendants service des consommateurs plus tard, avec CrudRepository de Printemps et géré les opérations de Service de Couche?

Extrait de la demande qui provoque une exception:

    User user = userService.findByLogin(login);
    categoryService.deleteByUser(user);

EDIT: j'ai essayé d'utiliser EntityManager::merge, mais avec pas de chance:

@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());
    }
}

Services (injecté avec @Autowired):
Le service à l'usager:

package <package>.service.jpa;
import com.google.common.collect.Lists;
import <package>.entity.User;
import <package>.repository.UserRepository;
import <package>.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<User> 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);
}
}

Catégorie de service:

package <package>.service.jpa;
import <package>.entity.Category;
import <package>.entity.User;
import <package>.repository.CategoryRepository;
import <package>.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());
}
}

Entités:
Utilisateur:

package <package>.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<Category> categories = new HashSet<Category>();
private Set<CategoryFeed> categoryFeeds = new HashSet<CategoryFeed>();
@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<Category> getCategories() {
return categories;
}
public void setCategories(Set<Category> categories) {
this.categories = categories;
}
public void addCategory(Category category) {
categories.add(category);
}
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
public Set<CategoryFeed> getCategoryFeeds() {
return categoryFeeds;
}
public void setCategoryFeeds(Set<CategoryFeed> 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;
}
}

Catégorie:

package <package>.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<CategoryFeed> feeds = new HashSet<CategoryFeed>();
@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<CategoryFeed> getFeeds() {
return feeds;
}
public void setFeeds(Set<CategoryFeed> 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;
}
}