Spring/Hibernate getting List of Objects containing lists - java

I'm trying to get a list of objects from database using Hibernate but something seems weird for me.
In the DB I have 5 Runs with 3 Positions each.
When I get the List of runs from RunDao I obtain a list of 15 Run objects ! The three first runs have the same ID.
In my case I just want to get the 5 Runs. Am I doing something wrong ?
How to get only the 5 runs ?
Thanks a lot
Here are my classes Run / Position / RunDao :
Run.java
#Entity
#Table(name="kr_runs")
public class Run {
private long id;
private Date date;
private int indexedPages;
private int pr;
#JsonIgnore
private Site site;
private Set<Position> positions = new HashSet<Position>(0);
public Run() {
}
#Id
#GeneratedValue
#Column(name="id")
public long getId() {
return id;
}
public void setId( long id ) {
this.id = id;
}
#Temporal(value=TemporalType.TIMESTAMP)
public Date getDate() {
return date;
}
public void setDate( Date date ) {
this.date = date;
}
#Column(name="indexed_pages")
public int getIndexedPages() {
return indexedPages;
}
public void setIndexedPages( int indexedPages ) {
this.indexedPages = indexedPages;
}
#Column
public int getPr() {
return pr;
}
public void setPr( int pr ) {
this.pr = pr;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "kr_site_id", nullable = false)
public Site getSite() {
return site;
}
public void setSite( Site site ) {
this.site = site;
}
#Cascade({CascadeType.ALL})
#OneToMany(fetch = FetchType.EAGER, mappedBy = "run")
public Set<Position> getPositions() {
return positions;
}
public void setPositions( Set<Position> positions ) {
this.positions = positions;
}
}
Position.java
#Entity
#Table(name="kr_positions")
public class Position {
private long id;
private int pos;
private String url;
#JsonIgnore
private Run run;
private Keyword keyword;
public Position() {
}
#Id
#GeneratedValue
#Column(name="id")
public long getId() {
return id;
}
public void setId( long id ) {
this.id = id;
}
#Column
public int getPos() {
return pos;
}
public void setPos( int pos ) {
this.pos = pos;
}
#Column
public String getUrl() {
return url;
}
public void setUrl( String url ) {
this.url = url;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "kr_run_id", nullable = false)
public Run getRun() {
return run;
}
public void setRun( Run run ) {
this.run = run;
}
//#Cascade({CascadeType.SAVE_UPDATE})
//#OneToOne(mappedBy="position")
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "kr_keyword_id", nullable = false)
public Keyword getKeyword() {
return keyword;
}
public void setKeyword( Keyword keyword ) {
this.keyword = keyword;
}
}
RunDao.java
#Transactional
public class RunDao extends HibernateDao<Run, Long> implements IRunDao {
public List<Run> find( long siteID, Date date_start, Date date_end ) {
Criteria cr = currentSession().createCriteria(Run.class);
cr.add(Restrictions.eq("site.id", siteID));
cr.add(Restrictions.ge("date",date_start));
cr.add(Restrictions.lt("date",date_end));
List<Run> list = (List<Run>) cr.list();
if (list.isEmpty()) return null;
else return list;
}
}
Solved
Thanks to the help of Guillaume I found a solution.
I replaced in the Run class :
#OneToMany(fetch = FetchType.EAGER, mappedBy = "run")
by
#OneToMany(fetch = FetchType.LAZY, mappedBy = "run")
In my RunsService class when I get the Runs from DAO I pull the lazy collection :
// Get data from DAO
List<Run> list = runDao.find(siteID, cal.getTime(), date_today);
for(Run run : list)
{
Hibernate.initialize(run.getPositions()); // run.getPositions().size(); if you are note in #Transactional
}

Everything in your code looks correct. The only thing I'm not too certain about #OneToMany(fetch = FetchType.EAGER ... since I've had bugs in the past with EAGER fetch types.
Try to leave it LAZY and add a fetch join in your criteria query instead.

Related

JPA update a object creates a new one in a ManyToMany Relation

I'm having issues while trying to update objects with JPA. The problem instead of updating an existing object, it creates new ones along with new embedded data.
Here is my java code:
First entity
#Entity
#Table(name = "worksite")
public class Worksite {
private long id;
private String name;
private Double longitude;
private Double latitude;
private Set<WorksiteDevice> worksiteDevices = new HashSet<WorksiteDevice>();
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
#Column(name = "worksite_id")
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getLongitude() {
return longitude;
}
public void setLongitude(Double longitude) {
this.longitude = longitude;
}
public Double getLatitude() {
return latitude;
}
public void setLatitude(String latitude) {
this.latitude = latitude;
}
#OneToMany(mappedBy = "worksite", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true )
public Set<WorksiteDevice> getWorksiteDevices() {
return worksiteDevices;
}
public void setWorksiteDevices(Set<WorksiteDevice> worksiteDevices) {
this.worksiteDevices = worksiteDevices;
}
}
Second Entity:
the device name has a unique constraint in the database. This is to prevent the user from entering the same device multiple times
#Entity
#Table(name = "device")
public class Device {
private long id;
private String DeviceName;
private Set<WorksiteDevice> worksiteDevices = new HashSet<WorksiteDevice>();
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
#Column(name = "device_id")
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getDeviceName() {
return name;
}
public void setName(String name) {
this.deviceName = name;
}
#OneToMany(mappedBy = "device", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
public Set<WorksiteDevice> getWorksiteDevices() {
return worksiteDevices;
}
public void setWorksiteDevices(Set<WorksiteDevice> worksiteDevices) {
this.worksiteDevices = worksiteDevices;
}
Join Table:
#Entity
#Table(name = "worksite_device")
public class WorksiteDevice {
private long id;
private Worksite worksite;
private Device device;
// additional fields
private Integer deviceCount;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
#Column(name = "worksite_device_id")
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "worksite_id")
private Worksite worksite;
public void setWorksite(Worksite worksite) {
this.worksite = worksite;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "device_id")
public void setDevice(Device device) {
this.device = device;
}
public Integer getDeviceCount() {
return deviceCount;
}
public void setDeviceCount(Integer deviceCount) {
this.deviceCount = deviceCount;
}
}
I have a DTO class in which I get from the user interface the name of the devices and the number of devices used in a worksite.
public class WorksiteDeviceDTO extends BaseDTO{
private Long id;
private int deviceCount;
private String deviceName;
private Worksite worksite;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Integer getDeviceCount() {
return deviceCount;
}
public void setDeviceCount(Integer deviceCount) {
this.deviceCount = deviceCount;
}
public String getDeviceName() {
return deviceName;
}
public void setDeviceName(String deviceName) {
deviceName = deviceName;
}
}
I save the DTO objects in a list that I iterate before saving in the database. Here is how i do this:
I save first the worksite object and then the number of devices and names used in a worksite
worksiteService.saveWorksite(worksite);
final Map<String, Geraete> deviceByName = worksiteDeviceDtos.stream()
.map(worksiteDeviceDTO::getDeviceName)
.map(this::getOrSaveDeviceByName)
.collect(Collectors.toMap(
Device::getDeviceName,
Function.identity()));
worksiteDeviceDtos.forEach(worksiteDeviceDTO -> {
final WorksiteDevice toSave = new WorksiteDevice();
toSave.setWorksite(worksite);
toSave.setDevice(deviceByName.get(worksiteDeviceDTO.getDeviceName()));
toSave.setDeviceCount(worksiteDeviceDTO.getDeviceCount());
worksiteDeviceService.saveWorksiteDevice(toSave);
I check with this Method if a Devicename already in a Database exist. If so, I'll get it back. If not, I create a new Object with the new name.
#Transactional
public Device getOrSaveDeviceByName(String DeviceName) {
return DeviceNameService.findByName(DeviceName)
.orElseGet(() -> geraeteService.saveNewGeraetWithName(DeviceName));
}
when I change the name of a device in the user interface and I keep the number of devices, a new object is created with the modified name. I don't know how to solve this problem. Someone would have an idea. I also tried to work with a compound key but I had the same problem
It seems you are creating and saving a new instance all the time, regardless if you "found" a device by that name. You should filter out the elements that you found.

Hibernate error: Illegal Attempt to deference collection

Hello I have a one to many relationship between a reservation and rooms and its unidirectional. A reservation might have one to several rooms. Now I'm trying to search if a room is available based on certain dates, and type of room(i.e a king or queen).
My solution:
Find Rooms that are not present in the reservation table based and also based on the date criteria.
Room model:
#Entity
#Table(name="room")
public class Room implements java.io.Serializable {
private static final long serialVersionUID = 10L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="roomId", nullable = false)
private long Id;
#Column(name="roomNumber", length = 4, nullable = false) //room number with max length of 4 digits
private String roomNumber;
#Column(name="type", nullable = false, length=10) //queen or king
private String roomType;
#Column(name="properties", nullable = false, length=15) //smoking or non-smoking
private String roomProperties;
#Column(name="price", columnDefinition = "DECIMAL(10,2)", nullable = false) //sets the precision of price to 2 decimal places
private double price;
public Room() {}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public long getId() {
return Id;
}
public void setId(long id) {
this.Id = id;
}
public String getRoomNumber() {
return roomNumber;
}
public void setRoomNumber(String roomNumber) {
this.roomNumber = roomNumber;
}
public String getRoomType() {
return roomType;
}
public void setRoomType(String roomType) {
this.roomType = roomType;
}
public String getRoomProperties() {
return roomProperties;
}
public void setRoomProperties(String roomProperties) {
this.roomProperties = roomProperties;
}
}
Reservation Table:
#Entity
#Table(name="Reservation")
public class Reservation implements Serializable {
private static final Long serialVersionUID = 100L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="reservation_Id", nullable = false)
private long Id;
public long getId() {
return Id;
}
public void setId(long id) {
Id = id;
}
#Column(name="CheckInDate")
private Date checkInDate;
#Column(name="CheckOutDate")
private Date checkOutDate;
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "guestId", nullable = false)
private Guest guest;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinTable(name = "ReservedRooms", joinColumns = {#JoinColumn(name="resId",
referencedColumnName = "reservation_Id")}, inverseJoinColumns = {#JoinColumn(name="roomId",
referencedColumnName = "roomId")})
private List<Room> roomList;
#Column(name="roomsWanted")
private int roomsWanted;
public int getRoomsWanted() {
return roomsWanted;
}
public void setRoomsWanted(int roomsWanted) {
this.roomsWanted = roomsWanted;
}
public Date getCheckInDate() {
return checkInDate;
}
public void setCheckInDate(Date checkInDate) {
this.checkInDate = checkInDate;
}
public Date getCheckOutDate() {
return checkOutDate;
}
public void setCheckOutDate(Date checkOutDate) {
this.checkOutDate = checkOutDate;
}
public Guest getGuest() {
return guest;
}
public void setGuest(Guest guest) {
this.guest = guest;
}
public List<Room> getRoomList() {
return roomList;
}
public void setRoomList(List<Room> roomList) {
this.roomList = roomList;
}
}
Now method to perform the search availability:
#Override
#Transactional
#SuppressWarnings("unchecked")
public boolean checkAvailability(SearchCriteria searchCriteria) {
String hql = "from Room as r where r.roomType = :roomType1 and r.roomProperties = :roomProperties1 " +
"and r.Id not in (Select res.roomList.Id from Reservation as res left outer join res.roomList " +
"where res.checkInDate <=:checkInDate1 and res.checkOutDate >= :checkOutDate1 " +
" and R.Id = res.roomList.Id) ";
Query query = getSession().createQuery(hql);
query.setParameter("roomType1", searchCriteria.getRoomType());
query.setParameter("roomProperties1", searchCriteria.getRoomProperties());
query.setParameter("checkInDate1", searchCriteria.getCheckInDate());
query.setParameter("checkOutDate1", searchCriteria.getCheckOutDate());
List<Room> roomList = query.list();
if(roomList.isEmpty()) {
return true;
}
return false;
}
But it complains and gives the error:
illegal attempt to dereference collection [reservatio1_.reservation_Id.roomList] with element property reference [Id]
Please what I'm doing wrong as I'm new to hibernate
When you join a collection, you have to name it. You can't use it directly (dereference).
in (Select ROOMS.Id from Reservation as res
left outer join res.roomList AS ROOMS
where res.checkInDate <=:checkInDate1 and res.checkOutDate >= :checkOutDate1
and R.Id = ROOMS.Id)

How to return list of entities when I query to the view

I have two entities that related with One to Many connection. One is Path another is Point, one path can have few points. And I have view on MySQL side that joined those tables using join table. I need to get the result of query to that view. Here is first
#Entity
#Table(name = "paths")
public class Path {
#JsonIgnore
#Id
#Column(name="id")
#GeneratedValue(strategy=GenerationType.AUTO)
private Long pathID;
#Column(name="path_name")
private String pathName;
#Column(name="path_type")
private Long pathType;
#OneToOne(fetch = FetchType.EAGER)
#JoinColumn(name="uid")
#JsonIgnore
private User owner;
#Column(name="path_status")
private Long pathStatus;
#Column(name="description")
private String pathDescription;
#Column(name="created")
private Long created;
#OneToMany(mappedBy = "primaryKey.point", cascade = CascadeType.ALL)
private Set<PathPoints> pathPoints = new HashSet<PathPoints>();
public Long getPathID(){
return this.pathID;
}
public void setPathID(Long pathID){
this.pathID = pathID;
}
public String getPathName(){
return this.pathName;
}
public void setPathName(String pathName){
this.pathName = pathName;
}
public Long getPathType(){
return this.pathType;
}
public void setPathType(Long pathType){
this.pathType = pathType;
}
public Long getPathStatus(){
return this.pathStatus;
}
public void setPathStatus(Long pathStatus){
this.pathStatus = pathStatus;
}
public String getPathDescription(){
return this.pathDescription;
}
public void setPathDescription(String pathDescription){
this.pathDescription = pathDescription;
}
public Long getCreated(){
return this.created;
}
public void setCreated(Long created){
this.created = created;
}
public Set<PathPoints> getPathPoints() {
return pathPoints;
}
public void setPathPoints(Set<PathPoints> pathPoints) {
this.pathPoints = pathPoints;
}
public User getOwner() {
return owner;
}
public void setOwner(User owner) {
this.owner = owner;
}
}
Here is second
#Entity
#Table(name = "path_points")
#AssociationOverrides({
#AssociationOverride(name = "primaryKey.point", joinColumns = #JoinColumn(name = "point_id")),
#AssociationOverride(name = "primaryKey.path", joinColumns = #JoinColumn(name = "path_id"))
})
public class PathPoints{
private PathPointID primaryKey = new PathPointID();
private Long endTime;
private Long startTime;
#Column(name="end_time")
public Long getEndTime() {
return endTime;
}
public void setEndTime(Long endTime) {
this.endTime = endTime;
}
#Column(name="start_time")
public Long getStartTime() {
return startTime;
}
public void setStartTime(Long startTime) {
this.startTime = startTime;
}
#JsonIgnore
#EmbeddedId
public PathPointID getPrimaryKey() {
return primaryKey;
}
public void setPrimaryKey(PathPointID primaryKey) {
this.primaryKey = primaryKey;
}
#Transient
public Point getPoint() {
return primaryKey.getPoint();
}
public void setPoint(Point point) {
this.primaryKey.setPoint(point);;
}
#JsonIgnore
#Transient
public Path getPath() {
return primaryKey.getPath();
}
public void setPath(Path path) {
this.primaryKey.setPath(path);;
}
}
And that is ID class
#Embeddable
public class PathPointID implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private Point point;
private Path path;
#ManyToOne(cascade = CascadeType.ALL)
public Point getPoint() {
return point;
}
public void setPoint(Point point) {
this.point = point;
}
#ManyToOne(cascade = CascadeType.ALL)
public Path getPath() {
return path;
}
public void setPath(Path path) {
this.path = path;
}
}
You need to create third entity class and make jpa/hibernate operations with it.
#Entity
#Table(name = "your_view_name")
public class YourView {
#Column(name="someColumnFromYourView")
private String someColumnFromYourView;
#Transient
private List<Point> points;
...
}
and then do
YourView view = ...//get this view data by some parameters
view.setPoints(yourDaoMethodToGetPoints(view));
you can see this example. I'm using PostgreSQL and JPA 2.1 here.I wrote a view on the database and mapped it to JPA entity.There one thing you need to remember - you cannot do write operations on this view.

Getting #Id of lazy-loaded #ManyToOne entity allways returns null

I am using Hibernate 4.3.8.Final and have problem with retrieving #Id property of lazy fetched property: For attached classes calling aidConfiguration.getChipApplication().getId() allways returns null. Other properties, eg. aidConfiguration.getChipApplication().getVersion() returns correctly the value from DB. If chipApplication is not lazy loaded (see the comment in the code), then aidConfiguration.getChipApplication().getId() returns correct non-null value.
What am I dong wrong?
BTW I need it to be lazy.
BaseEntity:
#MappedSuperclass
public class BaseEntity implements Serializable {
#Id
#Column(name = "ID", unique = true)
#Size(min = 1, max = 255)
private String id;
#PrePersist
public final void generateUuid() {
if (this.getId() == null) {
this.setId(UUID.randomUUID().toString());
}
}
public final String getId() {
return id;
}
public final void setId(final String id) {
this.id = id;
}
}
AidConfiguration:
#Entity
#Audited
public class AidConfiguration extends BaseEntity {
#Column
#NotBlank
private String name;
#NotNull
#ManyToOne(fetch = FetchType.LAZY) // if it is EAGER (defaut) then then aidConfiguration.getChipApplication().getId() returns correctly non-null value
private ChipApplication chipApplication;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "aidConfiguration", cascade = CascadeType.ALL) // cascade for auto-saving and deleting items
private List<AidConfigurationItem> aidConfigurationItems;
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
public ChipApplication getChipApplication() {
return chipApplication;
}
public void setChipApplication(final ChipApplication chipApplication) {
this.chipApplication = chipApplication;
}
public List<AidConfigurationItem> getAidConfigurationItems() {
return aidConfigurationItems;
}
public void setAidConfigurationItems(final List<AidConfigurationItem> aidConfigurationItems) {
this.aidConfigurationItems = aidConfigurationItems;
}
}
ChipApplication:
#Entity
#Audited
public class ChipApplication extends BaseEntity {
#Column
#NotBlank(message = "Aid can not be empty")
private String aid;
#Column
#NotBlank(message = "Product can not be empty")
private String product;
#Column
#NotBlank(message = "Version can not be empty")
private String version;
#NotNull(message = "Network is mandatory")
#ManyToOne(fetch = FetchType.LAZY)
private Network network;
#ManyToMany(fetch = FetchType.EAGER)
private List<AidTag> aidTags;
public String getAid() {
return aid;
}
public void setAid(final String aid) {
this.aid = aid;
}
public String getProduct() {
return product;
}
public void setProduct(final String product) {
this.product = product;
}
public String getVersion() {
return version;
}
public void setVersion(final String version) {
this.version = version;
}
public Network getNetwork() {
return network;
}
public void setNetwork(final Network network) {
this.network = network;
}
public List<AidTag> getAidTags() {
return aidTags;
}
public void setAidTags(final List<AidTag> aidTags) {
this.aidTags = aidTags;
}
}
Bit late, but the issue HH-9588 is still unresolved, and I just had the same issue (XML mapping rather than annotations, though).
Could not get the id from the getter when the binding was lazy. Got it when eager or fetch join.
Fixed it by getting rid of the "final" modifier on the getId() accessor. (final here was an attempt to protect the way primary keys/identifiers are defined in the superclass for all the entities)
before :
public abstract class Foo {
Long id;
public final Long getId() {
return id;
}
protected final void setId( Long id ){
this.id = id;
}
...
after :
public abstract class Foo {
Long id;
// No more final
public Long getId() {
return id;
}
// No more final
protected void setId( Long id ){
this.id = id;
}
...
Now, I can get the Id with a lazy binding as well.
Seems to me that this "final" modifier does not allow Hibernate to proxy this accessor as intended. The other accessors being not "final", one can access their values from the proxy.
So, I wonder whether HH-9588 is really a bug or a misunderstanding of the hibernate ways ?
That seems a bug, if you do not miss anything. I would report it on Hibernate's bug tracking system. It would be nice if you would update this answer afterwards with a link to the bug.

JsonMappingException with Arrays of object in spring-jpa

i get an error when i try to get an item from my dbms. following error
com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: com.pharmawizardcabinet.core.entity.cabinet.Cabinet.listaFarmaci, could not initialize proxy - no Session (through reference chain: com.pharmawizardcabinet.web.beans.ResponseCabinet["cabinet"]->com.pharmawizardcabinet.core.entity.cabinet.Cabinet["listaFarmaci"])
this is my conteiner
#Entity
#Table(name = "Cabinet")
public class Cabinet implements Serializable {
private static final long serialVersionUID = 7311927404447970875L;
#Id
#Column(name = "Id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long Id;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "cabinet")
private List<Farmaco> listaFarmaci;
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "user")
private User user;
#Column(name = "timestamp")
#Temporal(TemporalType.DATE)
private Date setLastModified;
public Cabinet() {
}
#PostPersist
#PostUpdate
private void setLastUpdate() {
this.setLastModified = new Date();
}
public List<Farmaco> getListaFarmaci() {
return listaFarmaci;
}
public void setListaFarmaci(List<Farmaco> listaFarmaci) {
this.listaFarmaci = listaFarmaci;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Long getId() {
return Id;
}
public void setId(Long id) {
Id = id;
}
public Date getSetLastModified() {
return setLastModified;
}
public void setSetLastModified(Date setLastModified) {
this.setLastModified = setLastModified;
}
}
and this is the item
#Entity
#Table(name = "Farmaco")
public class Farmaco implements Serializable {
private static final long serialVersionUID = -152536676742398255L;
public Farmaco() {
// TODO Auto-generated constructor stub
}
#Column(name = "nome_farmaco")
private String nome;
#Column(name = "codice")
private String codice;
#Column(name = "azienda")
private String azienda;
#Id
#Column(name = "Id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long Id;
#Column(name = "scadenza")
#Temporal(TemporalType.DATE)
private Date scadenza;
#Enumerated(EnumType.STRING)
#Column(name = "posologia")
private Posologia posologia;
#Column(name = "quantita")
private Integer quantita;
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "note")
private Note note;
#ManyToOne(cascade =CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "cabinet_id")
private Cabinet cabinet;
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public String getCodice() {
return codice;
}
public void setCodice(String codice) {
this.codice = codice;
}
public String getAzienda() {
return azienda;
}
public void setAzienda(String azienda) {
this.azienda = azienda;
}
public Long getId() {
return Id;
}
public void setId(Long id) {
Id = id;
}
public Date getScadenza() {
return scadenza;
}
public void setScadenza(Date scadenza) {
this.scadenza = scadenza;
}
public Posologia getPosologia() {
return posologia;
}
public void setPosologia(Posologia posologia) {
this.posologia = posologia;
}
public Integer getQuantita() {
return quantita;
}
public void setQuantita(Integer quantita) {
this.quantita = quantita;
}
public Note getNote() {
return note;
}
public void setNote(Note note) {
this.note = note;
}
public Cabinet getCabinet() {
return cabinet;
}
public void setCabinet(Cabinet cabinet) {
this.cabinet = cabinet;
}
}
controller is this
#Component("managerCabinet")
public class ManagerCabinet {
private static Logger logger = Logger.getLogger(ManagerCabinet.class);
#PersistenceContext(name = "pwcabinet-jpa")
private EntityManager entityManager;
#Transactional
public Cabinet getCabinetByUser(User user) {
logger.debug("[getCabinetByUser] user: " + user.getId());
return _getCabinetByUser(user);
}
private Cabinet _getCabinetByUser(User user) {
logger.debug("[_getCabinetByUser] user: " + user.getId());
User find = entityManager.find(User.class, user.getId());
Query searchCabinetByUser = entityManager.createQuery("Select c from Cabinet c where c.user = :userId", Cabinet.class);
searchCabinetByUser.setParameter("userId", find);
Cabinet cabinetSearch = (Cabinet) searchCabinetByUser.getSingleResult();
cabinetSearch.setUser(find);
return cabinetSearch;
}
}
but i continue to get error.
if i use the annotation #JsonIgnore in this way
#JsonIgnore
public List<Farmaco> getListaFarmaci() {
return listaFarmaci;
}
they works, but i need this information in my result. how i solve it?
When your method private Cabinet _getCabinetByUser(User user) returns the Cabinet instance is then in the 'detached' state, viz. is no longer associated with a persistence context.
When an item is in a detached state non-eagerly fetched associations can longer be accessed.
As the default fetch for #OneToMany is Lazy then in your case
#OneToMany(cascade = CascadeType.ALL, mappedBy = "cabinet")
private List<Farmaco> listaFarmaci;
the field listaFarmaci can no longer be accessed once the loaded Cabinet is detached from the persistence context.
You have various means of dealing with this which would include:
Marking the field as being eagerly fetched (not good as will always be eagerly fetched regardless of whether required or not).
Forcing the persistence context to remain open until all processing is done typically referred to as the OpenSessionInView pattern (or anti-pattern) depending on your point of view: http://java.dzone.com/articles/open-session-view-design
Ensuring all data required for use case is initialized before detachment. There are various ways of achieving this:
Simply accessing the collection is some way e.g. by calling size() but this may not work with all JPA providers.
Specifying FETCH JOIN in your JPQL query which loads the Cabinet (although this has side effects). http://en.wikibooks.org/wiki/Java_Persistence/Relationships#Join_Fetching

Categories

Resources