Java JPA error: Missing mapping for field - java

I'm having problem with Java JPA with persisting entity relationship object. My table: Rezervacija consists of (IDrez, idKorisnik, idKompanija, idKomponenta). I'm persisting new object (and i got all 3 params after IDRez from database, and it's okay. p.s. idRez is being autoincrement by database.
Here's my code:
public class Komponenta implements Serializable {
#Id
private Integer idKom;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "idKomponenta")
private Collection<Rezervacija> rezervacijaCollection = new ArrayList<>();
}
public class Korisnik implements Serializable {
#Id
private Integer idKor;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "idKorisnik")
private Collection<Rezervacija> rezervacijaKorisnikCollection = new ArrayList<>();
#OneToMany(cascade = CascadeType.ALL, mappedBy = "idKompanija")
private Collection<Rezervacija> rezervacijaKompanijaCollection = new ArrayList<>();
}
public class Rezervacija implements Serializable {
#Id
private Integer idRez;
#JoinColumn(name = "idKom", referencedColumnName = "idKomponenta")
#ManyToOne(cascade = CascadeType.ALL)
private Komponenta idKomponenta;
#JoinColumn(name = "idKor", referencedColumnName = "idKorisnik")
#ManyToOne(cascade = CascadeType.ALL)
private Korisnik idKorisnik;
#JoinColumn(name = "idKompanija", referencedColumnName = "idKompanija")
#ManyToOne(cascade = CascadeType.ALL)
private Korisnik idKompanija;
}
// executable code part em - entitymanager
entityManager.getTransaction().begin();
Korisnik korisnik = entityManager.find(Korisnik.class, 1);
Korisnik kompanija = entityManager.find(Korisnik.class, 2);
Komponenta komponenta = entityManager.find(Komponenta.class, 1);
Rezervacija rez = new Rezervacija(korisnik, kompanija, komponenta);
entityManager.persist(rez);
entityManager.getTransaction().commit();
When I run this code I've got console out error:
Exception Description: Missing mapping for field [komponenta.idKomponenta].

Related

Hibernate JPA #OneToMany join on 2 columns with OR statement in Entity

I have the following class:
public class Nomenclature extends BaseEntity {
#Id
#Column(name = "NOMENCLATURE_CODE")
private String nomenclatureCode;
#OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.ALL}, mappedBy = "nomenclatureCode", orphanRemoval = true)
private List<Cumul> cumuls = new ArrayList<>();
}
I want to join the following Cumul class on 2 columns WHERE cumul.nomenclatureCode = nomenclature.nomenclatureCode OR cumul.nomenclatureCodeAllowedCumul = nomenclature.nomenclatureCode
public class Cumul extends BaseEntity {
#Id
#Column(columnDefinition = "NUMERIC")
#GeneratedValue(generator = "CUMUL", strategy = GenerationType.SEQUENCE)
private Long id;
#Column(name = "NOMENCLATURE_CODE")
private String nomenclatureCode;
#Column(name = "NOMENCLATURE_CODE_ALLOWED_CUMUL")
private String nomenclatureCodeAllowedCumul;
#OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.ALL},orphanRemoval = true)
#JoinColumns(
{
#JoinColumn(name = "nomenclature_code", referencedColumnName = "nomenclature_code"),
#JoinColumn(name = "nomenclature_code_allowed_cumul", referencedColumnName = "nomenclature_code")
})
private List<Cumul> cumuls = new ArrayList<>();
Worked but this an AND statement not an OR what I was looking for

Hibernate OneToMany mapping & Query generation : More than one row with the given identifier was found

I am using spring-boot-starter-data-jpa 1.5.1.RELEASE which internally uses hibernate-core 5.0.11.Final
My entity looks like this:
AreaDto
#Entity
#Table(name = "AREA")
#EntityListeners(AuditingEntityListener.class)
public class AreaDto {
#Id
#Column(name = "AREA_ROWID")
private String areaRowId;
#OneToMany(cascade = CascadeType.DETACH)
#JoinColumn(name = "AREA_ROWID")
private Collection<FestivalDto> festival;
#OneToMany(cascade = CascadeType.DETACH, mappedBy = "area")
private Collection<ActionDto> actions;
#OneToMany(fetch = FetchType.LAZY)
#JoinTable(name = "FESTIVAL", joinColumns = {
#JoinColumn(name = "AREA_ROWID", referencedColumnName = "AREA_ROWID")}, inverseJoinColumns = {
#JoinColumn(name = "FESTIVAL_ROWID", referencedColumnName = "FESTIVAL_ROWID")})
private Collection<ActionDto> festivalActions;
}
FestivalDto
#Entity
#EntityListeners(AuditingEntityListener.class)
#Table(name = "FESTIVAL")
public class FestivalDto {
#Id
#Column(name = "FESTIVAL_ROWID")
#GeneratedValue(generator = "FESTIVAL_ROWID_SEQ")
private Long festivalRowId;
#ManyToOne(cascade = CascadeType.DETACH, fetch = FetchType.LAZY, optional = true)
#JoinColumn(name = "AREA_ROWID")
private AreaDto area;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "festival")
private Collection<ActionDto> actions = Lists.newArrayList();
}
ActionDto
#Entity
#EntityListeners(AuditingEntityListener.class)
#Table(name = "ACTION")
public class ActionDto implements Serializable {
...
#Id
#Column(name = "ACTION_ID")
#GeneratedValue(generator = "ACTION_ID_SEQ")
private Long actionId;
#Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
#ManyToOne(cascade = DETACH, fetch = FetchType.LAZY)
#JoinColumn(name = "FESTIVAL_ROWID")
private FestivalDto festival;
#Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
#ManyToOne(cascade = DETACH, fetch = FetchType.LAZY)
#JoinColumn(name = "AREA_ROWID")
private AreaDto area;
}
I'm trying to make sense of the below ideas:
What is the strategy used by hibernate to decide on the festival_rowid (or festival_row ids) used to get all the associated action? How will hibernate generated SQL query vary if i change festivalActions fetch strategies between LAZY and EAGER? I know about proxying, collection proxying and all, my question is specific to how those sql is generated and how it may have an impact on deciding the value of bind parameter.
Is my mapping accurate or should I be using a multimap for this relationship since an area could have multiple festival and each festival could have multiple actions
Background:
I am getting below error which goes away if I change the fetch type from LAZY to EAGER. Hoping to understand the behaviour for gaining some confidence in the fix. I have read SO and error
org.hibernate.HibernateException: More than one row with the given identifier was found: data.dto.ActionDto#280856b5
This mapping does not make much sense. You can't map festivalActions this way because there is no way to persist the state properly through such a mapping. Also festival in AreaDto should be mapped by the area in FestivalDto. Try the following instead:
#Entity
#Table(name = "AREA")
#EntityListeners(AuditingEntityListener.class)
public class AreaDto {
#Id
#Column(name = "AREA_ROWID")
private String areaRowId;
#OneToMany(cascade = CascadeType.DETACH, mappedBy = "area")
private Collection<FestivalDto> festival;
#OneToMany(cascade = CascadeType.DETACH, mappedBy = "area")
private Collection<ActionDto> actions;
public Collection<ActionDto> getFestivalActions() {
return festival.stream().flatMap(f -> f.actions.stream()).collect(Collectors.toList());
}
}
#Entity
#EntityListeners(AuditingEntityListener.class)
#Table(name = "FESTIVAL")
public class FestivalDto {
#Id
#Column(name = "FESTIVAL_ROWID")
#GeneratedValue(generator = "FESTIVAL_ROWID_SEQ")
private Long festivalRowId;
#ManyToOne(cascade = CascadeType.DETACH, fetch = FetchType.LAZY, optional = true)
#JoinColumn(name = "AREA_ROWID")
private AreaDto area;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "festival")
private Collection<ActionDto> actions = Lists.newArrayList();
}
#Entity
#EntityListeners(AuditingEntityListener.class)
#Table(name = "ACTION")
public class ActionDto implements Serializable {
...
#Id
#Column(name = "ACTION_ID")
#GeneratedValue(generator = "ACTION_ID_SEQ")
private Long actionId;
#Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
#ManyToOne(cascade = DETACH, fetch = FetchType.LAZY)
#JoinColumn(name = "FESTIVAL_ROWID")
private FestivalDto festival;
#Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
#ManyToOne(cascade = DETACH, fetch = FetchType.LAZY)
#JoinColumn(name = "AREA_ROWID")
private AreaDto area;
}

detached entity passed to persist JPA Spring boot save

I'm triying to save a user class with company and areas selected. User has a many to many relation with company and many to many to areas.
It's giving me the error : detached entity passed to persist:
I'm not sure what is the problem
USER:
#Entity
#Table(name = "NPRO_USUARIOS")
public class User implements Serializable {
private static final long serialVersionUID = -1330075515340995797L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO, generator="user_seq_gen")
#SequenceGenerator(name="user_seq_gen", sequenceName="TELCO_NPRO_USER_SEQ")
#NotNull
private int id_usuario;
#NotNull
private String nombre_usuario;
#ManyToMany(cascade = {CascadeType.PERSIST,CascadeType.REMOVE, CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH })
#JoinTable(name = "NPRO_USUARIOS_SOCIEDADES_AREAS", joinColumns = #JoinColumn(name = "id_usuario"), inverseJoinColumns = #JoinColumn(name = "id_sociedad"))
private Set<Sociedad> listaSociedad;
#Transient
private String sociedades;
// Si el area es nula, el usuario estara asignado a todas las areas
#ManyToMany(cascade = {CascadeType.PERSIST,CascadeType.REMOVE, CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH })
#JoinTable(name = "NPRO_USUARIOS_SOCIEDADES_AREAS", joinColumns = #JoinColumn(name = "id_usuario"), inverseJoinColumns = #JoinColumn(name = "id_area"))
private Set<Area> listAreas;
#Transient
private String areas;
#NotNull
private String matricula_usuario;
#NotNull
private String email_usuario;
#ManyToMany(cascade = { CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH })
#JoinTable(name = "NPRO_PERFILES_USUARIOS", joinColumns = #JoinColumn(name = "id_usuario"), inverseJoinColumns = #JoinColumn(name = "id_rol"))
private Set<Role> listaRoles;
#ManyToMany(cascade = { CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH })
#JoinTable(name = "NPRO_PERFILES_USUARIOS", joinColumns = #JoinColumn(name = "id_usuario"), inverseJoinColumns = #JoinColumn(name = "id_pantalla"))
private Set<Pantalla> listaPantallas;
private LocalDateTime fecha_ultimo_acceso;
private String observaciones;
#JsonIgnore
#ManyToOne
#JoinColumn(name = "usuario_modif")
private User usuario_modif;
}
Compnay:
#Entity
#Table(name = "NPRO_MAESTRO_SOCIEDADES")
public class Sociedad implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#NotNull
private int id_sociedad;
#NotNull
private String cod_sociedad;
#NotNull
private String cod_sociedad_gl;
#NotNull
private String nombre_sociedad;
#NotNull
private String cif_sociedad;
private String observaciones;
#JsonIgnore
#ManyToOne
#JoinColumn(name = "usuario_modif")
private User usuario_modif;
private String activo;
#JsonIgnore
#ManyToMany(cascade = {CascadeType.PERSIST,CascadeType.REMOVE, CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH })
#JoinTable(name = "NPRO_USUARIOS_SOCIEDADES_AREAS", joinColumns = #JoinColumn(name = "id_sociedad"), inverseJoinColumns = #JoinColumn(name = "id_usuario"))
private Set<User> listaUsuarios;
}
Area:
#Entity
#Table(name = "NPRO_MAESTRO_AREAS")
public class Area implements Serializable {
private static final long serialVersionUID = -1330075515340995797L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO, generator="area_seq_gen")
#SequenceGenerator(name="area_seq_gen", sequenceName="TELCO_NPRO_AREAS_SEQ")
#NotNull
private int id_area;
#NotNull
private String nombre_area;
private LocalDateTime fecha_modif;
private String observaciones;
#JsonIgnore
#ManyToOne
#JoinColumn(name = "usuario_modif")
private User usuario_modif;
#NotNull
private String activo;
#ManyToOne
#JoinColumn(name="id_sociedad")
private Sociedad sociedad;
#JsonIgnore
#ManyToMany(cascade = {CascadeType.PERSIST,CascadeType.REMOVE, CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH })
#JoinTable(name = "NPRO_USUARIOS_SOCIEDADES_AREAS", joinColumns = #JoinColumn(name = "id_area"), inverseJoinColumns = #JoinColumn(name = "id_usuario"))
private Set<User> listaUsuarios;
}
I'm using springboot jpa repository save method
#Override
public User save(User user) {
return userRepository.save(user);
}
And this is the complete error :
2020-06-09 15:49:02.371 [nio-8080-exec-4] .m.m.a.ExceptionHandlerExceptionResolver : Resolved exception caused by Handler execution: org.springframework.dao.InvalidDataAccessApiUsageException: detached entity passed to persist: com.telefonica.npro.model.Area; nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: com.telefonica.npro.model.Area
Thanks in advance
EDIT :
I'm reading about the eror in this page
http://knowledgespleasure.blogspot.com/2015/06/understand-detached-entity-passed-to.html
And I guess my problem is the last one :
On the other hand, if requirement is never to add a new child if its not alredy in DB then CascadeType.PERSIST should be removed and cascade={CascadeType.MERGE,CascadeType.REFRESH} should be used
User is always related with the company and areas, and they already exist, they are not going to be new.
But if I remove PERSIST, it's triying to insert in an id null in the commun table
NPRO_USUARIOS_SOCIEDADES_AREAS
Any help ?
I will explain your problem for the #ManyToMany bidirectional relationship between User and Area entities.
A bidirectional #ManyToMany association should have an owning and a mappedBy side. The CascadeType should be present only on one side of this association.
As explained in this article, you need to have both sides in sync as otherwise, you break the Domain Model relationship consistency, and the entity state transitions are not guaranteed to work unless both sides are properly synchronized.
For this reason, the User entity defines the addArea and removeArea entity state synchronization methods.
So, you should correct your User - Area #ManyToMany mapping in this way:
#Entity
#Table(name = "NPRO_USUARIOS")
public class User implements Serializable {
// ...
#ManyToMany(cascade = {CascadeType.PERSIST,CascadeType.REMOVE, CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH })
#JoinTable(name = "NPRO_USUARIOS_SOCIEDADES_AREAS", joinColumns = #JoinColumn(name = "id_usuario"), inverseJoinColumns = #JoinColumn(name = "id_area"))
private Set<Area> listAreas;
public User()
{
listAreas = new HashSet<>();
}
public void addArea(Area area) {
listAreas.add(area);
area.getUsers().add(this);
}
public void removeArea(Area area) {
listAreas.remove(area);
area.getUsers().remove(this);
}
}
#Entity
#Table(name = "NPRO_MAESTRO_AREAS")
public class Area implements Serializable {
// ...
#JsonIgnore
#ManyToMany(mappedBy = "listAreas")
private Set<User> listaUsuarios;
}
And then you can save a new user in this way:
User user = new User();
// ...
Area area1 = new Area();
// ...
user.addArea(area1);
Area area2 = new Area();
// ...
user.addArea(area2);
userRepository.save(user);
The similar correction should be done for the User - Sociedad relationship.

Get primary key instead the whole object in OneToMany relationship

I have the following classes:
#Entity
#Table(name = "elements")
#Inheritance(strategy=InheritanceType.JOINED)
#XmlRootElement
public abstract class Elements implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "idelement")
private Integer idElement;
#Basic(optional = false)
#Column(name = "code")
private String code;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "idElement")
#Fetch(value = FetchMode.SUBSELECT)
private Collection<Alarms> alarmsCollection;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "idElement")
#Fetch(value = FetchMode.SUBSELECT)
private Collection<ElementsHistorical> elementsHistoricalCollection;
#ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST, mappedBy = "elementsCollection")
#Fetch(value = FetchMode.SUBSELECT)
private Collection<ElementsGroups> elementsGroupsCollection;
//Constructors, getters and setters
}
#Entity
#Table(name = "alarms")
#XmlRootElement(name = "Alarms")
public class Alarms implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "idalarm")
private Integer idAlarm;
#JoinColumn(name = "idelement", referencedColumnName = "idelement")
#ManyToOne(optional = false)
private Elements idElement;
//Constructors, getters and setters
}
I created a jersey webservice and a DAO class with CRUD operations to treat Alarms data. With this implementation, when I call GET method, I get the whole Elements object inside the Alarms one. This is the DAO method called:
public List<Alarms> getAlarms(){
Session session = SessionUtil.getSession();
Query query = session.createQuery("from Alarms");
List<Alarms> alarms = query.list();
session.close();
return alarms;
}
I don't want this fetch = FetchType.EAGER fetch type, as I just need the PK of Elements, but after some research this is the only way I found to make my service work.
I tried this and this approach, but I've not been able to make it work.
You can use left outer join fetch in you query.
Query query = session.createQuery("from Alarms alarm left outer join fetch alarm.idElement element");
Now you can keep fetch = FetchType.LAZY (which is default).
Try to add #XmlTransient annotation to fields in Elements class that you want to ignore.
like this :
#Entity
#Table(name = "elements")
#Inheritance(strategy=InheritanceType.JOINED)
#XmlRootElement
public abstract class Elements implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "idelement")
private Integer idElement;
#Basic(optional = false)
#Column(name = "code")
#XmlTransient
private String code;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "idElement")
#Fetch(value = FetchMode.SUBSELECT)
#XmlTransient
private Collection<Alarms> alarmsCollection;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "idElement")
#Fetch(value = FetchMode.SUBSELECT)
#XmlTransient
private Collection<ElementsHistorical> elementsHistoricalCollection;
#ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST, mappedBy = "elementsCollection")
#Fetch(value = FetchMode.SUBSELECT)
#XmlTransient
private Collection<ElementsGroups> elementsGroupsCollection;
//Constructors, getters and setters
}
You can use multiselect with Tuple, for select only specific columns.
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Tuple> cq = cb.createTupleQuery();
Root<Alarms> root = cq.from(Alarms.class);
CollectionJoin<Object, Object> joinCollection = root.joinCollection("alarmsCollection");
cq.multiselect(joinCollection.get("idElement"));
List<Tuple> tupleResult = entityManager.createQuery(cq).getResultList();
for (Tuple t : tupleResult) {
Long idElement = (Long) t.get(0);
}

JPA or CRUD Repository query in spring boot for many to many relation for persisting data

I'm having 3 entities City, Hotel and BookRoom with mapping as mentioned below:
public class BookRoom {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int bookID;
.....
.....
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name ="hotelID")
private Hotel hotel;
}
public class Hotel {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer hotelID;
....
....
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "Hotel_City", joinColumns = #JoinColumn(name = "hotelID", nullable = false), inverseJoinColumns = #JoinColumn(name = "cityID", nullable = false))
private Set<City> cities;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "hotel")
private Set<BookRoom> bookRoom;
}
public class City {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int cityID;
....
....
#ManyToMany(fetch = FetchType.LAZY, mappedBy = "cities")
private Set<Hotel> hotels;
}
And I'm using CRUD Repository for persisting
public interface BookRoomRepo extends CrudRepository<BookRoom, Integer> {
}
Now I have a existing data for hotel and city.
So while calling save() method of bookroom I'm getting:
Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: com.hbs.entity.Hotel
And my method for calling is as below:
#Override
public void run(String... arg0) throws Exception {
City city = new City();
Hotel hotel = new Hotel();
city.setCityID(4);
Set<City> cities = new HashSet<>();
cities.add(city);
hotel.setCities(cities );
hotel.setHotelID(2);
BookRoom bookRoom = new BookRoom();
bookRoom.setCheckInDate(new Date());
bookRoom.setCheckOutDate(new Date());
bookRoom.setCityN("Ranchi");
bookRoom.setNoOfRooms(1);
bookRoom.setHotel(hotel);
bookRoom.setUserName("Aman");
bookRoomRepo.save(bookRoom);
}
So my issue is that while adding BookRoom detail will it try to add records for Hotel and City inspite of data exist or not.
Try using the merge() method, and not the save() method. See https://spring.io/blog/2011/02/10/getting-started-with-spring-data-jpa/

Categories

Resources