1

I have a hibernate project that connects to two data sources and has a base dao. I use the base dao to derive generic daos for the data sources as well.

I have a service that fetches a join relationship and I am running into the following error when ever an entity has a one to many relationship. I am stuck in that I am not able to get the one to many relationship objects.

I used the apache commons beanutils to copy properties hoping it would do a deep copy but it does not work either. I am running out of ideas.

I read that I there is the option to use Open Session In View but I am not sure how to go about that.

Error

failed to lazily initialize a collection of role: com.sony.spe.mc.domain.OperationalUnit.user, could not initialize proxy - no Session

I have the following layers and files

Controller Layer

    @ApiOperation(value = "read", nickname = "getByID")
    @RequestMapping(value="/read", method = RequestMethod.GET)
    @ApiImplicitParams({
        @ApiImplicitParam(name = "id", value = "User's id", required = true, dataType = "int", paramType = "query")
    })
    @ApiResponses(value = { 
            @ApiResponse(code = 200, message = "Success", response = User.class),
            @ApiResponse(code = 500, message = "Failure")})
    @ResponseBody
    public UserProxy getByID(long id) {
        UserProxy user;
        try {               
            user = userService.fetchUserById(id);
        }
        catch(Exception ex) {
            ex.printStackTrace();
            return null;
        }
        return user;
    }

The Service Layer

User Service

@Service
@Transactional("fuseTransactionManager")
public class UserServiceImpl extends BaseFuseServiceImpl<User> implements UserService {
    @Autowired
    UserDao userDao;

    @Override 
    protected UserDao getDao() {
        return userDao;
    }

    @Override
    public UserProxy fetchUserById(long id) {
        try {
/***** ERROR HAPPENS HERE. THE USER OBJECT IS NOT ABLE TO GET THE ONE TO MANY OBJECTS even though I have @Transactional *****/
            User user = userDao.fetchEntityById(User.class, id);
            UserProxy userProxy = new UserProxy();
            BeanUtils.copyProperties(userProxy, user);
            return userProxy;
        } catch(Exception ex) {
            ex.printStackTrace();
            return null;
        }
    }
.....

Generic Fuse Service

@Service
public class BaseFuseServiceImpl<T extends Serializable> extends BaseServiceImpl<T> implements BaseFuseService<T> {
    @Autowired
    BaseFuseDao<T> baseFuseDao;

    @Override
    protected BaseFuseDao<T> getDao() {
        return baseFuseDao;
    }
}

Very generic service that the specific services implement

@Service
@Transactional("baseTransactionManager")
public abstract class BaseServiceImpl<T extends Serializable> implements BaseService<T> {
    protected abstract BaseDao<T> getDao();

    @Override
    public T fetchEntityById(Class<T> entityClass, long id) {
        return getDao().fetchEntityById(entityClass, id);
    }

User Entity. There is also a corresponding proxy object that is pretty much identical except it does not have the @Entity @Column annotations.

@Entity
@Table(name="USER")
//@AttributeOverride(name = "ID", column = @Column(name = "USER_ID",  nullable = false))
public class User extends BaseEntity {
//public class User implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 5236507646361562577L;

    @Id  
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "USER_ID")
    private long id;  

    @OneToMany(cascade=CascadeType.ALL)  
    @JoinTable(name="USER_OPERATIONALUNIT",  
        joinColumns = {@JoinColumn(name="USER_ID")},  
        inverseJoinColumns = {@JoinColumn(name="OPERATIONALUNIT_ID")}
    )  
    private Set<OperationalUnit> operationalUnit;
.... getters and setters
Harshal Patil
  • 6,659
  • 8
  • 41
  • 57
Sakib
  • 1,503
  • 4
  • 26
  • 39
  • You have a `@Transactional` annotation on your service class, and that's nice. But are you actually sure that transaction management is set up properly and the transactions actually start when they supposed to start (e.g. before entering the method `fetchUserById`)? – Nándor Előd Fekete Mar 17 '16 at 00:07
  • I am not too sure. Are there extra steps I should be taking to ensure that? – Sakib Mar 17 '16 at 19:07
  • Debug logging or debugging. Practically, if you break into the method which should be transactional, you would see in the stack frame the classes and methods responsible for transaction management. Try placing a breakpoint there and run it again to what happens. – Nándor Előd Fekete Mar 17 '16 at 20:46

1 Answers1

0

Why you want make all the methods @Transactional inside class. You can use @Transactional whenever it requires. For best practices use @Transactional over the method.

So in Your case there are 2 solutions:

1.By Fetching childs eagerly:

You need to pass fetchType Eagerly with your annotation i.e.

@OneToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER)

2. By using @Transactional:

Here you need to initialize you collection in current transaction i.e.

public UserProxy fetchUserById(long id) {
        try {
            User user = userDao.fetchEntityById(User.class, id);
// Here you need to initialize collection using getter method after retrieving object
            user.getOperationalUnit().size();
//Now you will get childs with your parent entity
                UserProxy userProxy = new UserProxy();
                BeanUtils.copyProperties(userProxy, user);
                return userProxy;
            } catch(Exception ex) {
                ex.printStackTrace();
                return null;
            }
        }

For more details about @Transactional Refer this link.

Community
  • 1
  • 1
Harshal Patil
  • 6,659
  • 8
  • 41
  • 57
  • I tried this too but I get the same error. Since it is a one to many relationship the operational unit also has a set of users which I keep with the one to many annotation. I tried to do the initialize and get size but then the operational unit cause the lazy loading error. I also tried fetching with eager and that results in inifinte loops. – Sakib Mar 17 '16 at 19:05
  • @Sakib Relationships in JPA are always unidirectional, unless you associate the parent with the child in both directions. – Harshal Patil Mar 18 '16 at 06:15