Reputation: 446
I am using Spring JPA to store a many-to-many relationship between User and Service with the table Acquisition. Since the bridge table contains additional columns I modelled it as having two many-to-one relationships. Both are bidirectional. Additionally the Acquisition entity has a one-to-one relationship with ServiceConfiguration.
There is no problem with saving or retrieving any of these entities. However when I try to delete the acquisition like this:
@Override
@Transactional
public void removeUsersServiceAcquisition(Long serviceId, User user) {
Service service = getService(serviceId);
Acquisition acquisition = findAcquisitionByServiceAndUser(service, user);
acquisitionRepository.delete(acquisition.getId());
log.info("\n retrieved acquisition {} ", acquisitionRepository.findOne(acquisition.getId()));
}
The change is not reflected in the database. The subsequent find within the above method returns null. But later in the code and in the database the record exists. There are no exceptions being thrown.
@Entity
@Table(name="ACQUISITION")
public class Acquisition implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name="id")
public Long getId() {
return id;
}
@ManyToOne
@JoinColumn(name="user_id")
public User getUser() {
return user;
}
@ManyToOne
@JoinColumn(name="service_id")
public Service getService() {
return service;
}
@OneToOne(mappedBy="acquisition")
public ServiceConfiguration getConfiguration() {
return configuration;
}
}
@Entity
@Table(name="USER")
public class User implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name="id")
public Long getId() {
return id;
}
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval=true)
public Set<Acquisition> getAcquisitions() {
return acquisitions;
}
}
@Entity
@Table(name="SERVICE")
public class Service implements Serializable{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name="id")
public Long getId() {
return id;
}
@OneToMany(mappedBy="service", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval= true)
public Set<Acquisition> getAcquisitions() {
return acquisitions;
}
}
@Entity
@Table(name="SERVICE_CONFIGURATION")
public class ServiceConfiguration implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name="id")
public Long getId() {
return id;
}
@OneToOne
@JoinColumn(name="acquisition_id")
public Acquisition getAcquisition() {
return acquisition;
}
public void setAcquisition(Acquisition acquisition) {
this.acquisition = acquisition;
}
}
Upvotes: 2
Views: 2018
Reputation: 446
Here is what I did to get this to work.
The remove method changed to first remove the acquisition from both relationships in which it participated:
@Transactional
public void removeUsersServiceAcquisition(Long serviceId, User user) {
Service service = getService(serviceId);
Acquisition acquisition = findAcquisitionByServiceAndUser(service, user);
service.getAcquisitions().remove(acquisition);
user.getAcquisitions().remove(acquisition);
acquisitionRepository.delete(acquisition.getId());
log.info("\n retrieved acquisition {} ", acquisitionRepository.findOne(acquisition.getId()));
}
This resulted in "no Session" Hibernate exception.
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.netstellar.sitesuite.serviceregistry.site.model.User.acquisitions, could not initialize proxy - no Session
Which I dealt with by adding fetch property to the User mapping. Not sure if this is the only way of addressing this exception.
@OneToMany(mappedBy = "user", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval=true)
public Set<Acquisition> getAcquisitions() {
return acquisitions;
}
Upvotes: 1