Lazy Initialization Exception on Initialize a Collection - JPA - java

I implement a simple SpringMVC application. As models I have Person and Event both get mapped to a H2 database.
For now I am able to store a Person object and an Event object as well. But when I am trying to store a list of Person to my Event object than I always get the exception:
failed to lazily initialize a collection, could not initialize proxy - no Session
My approach so far:
#Entity
public class Event implements Persistable<Long> {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String eventName;
#OneToMany(fetch = FetchType.EAGER)
#ElementCollection(targetClass = Member.class)
private List<Person> members = new ArrayList<>();
}
#Entity
public class Person implements Persistable<Long>{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String firstname;
private String lastname;
}
The goal is to select Person objects with a primefaces SelectManyMenu and store them to the List<Person> members of the event. When I add some Person objects to an Event via SQL than the SelectManyMenu pre-selects the added Person objects correctly. But when I select an additional Person object and call save then the exception appears.
First I thought my save-method doesn't work. But it has to work correctly because I am able to save Person objects and Event objects separately (without a Relationship between).

To map properly, you should map members field as #OneToMany(mappedBy = "event", fetch = ...), and add #ManyToOne Event event in your Person class. Also you can be certain about what fetching strategy needed to use by reading fetching strategies document.

Related

JpaRepository ManyToMany Deletion problem

I have two models: Events and NotificationUser.
An Event can have many Users and a User can have many Events. I build 2 Models.
Event
public class Event {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String name;
#ElementCollection
private List<Action> actions;
private String description;
#ManyToMany
private List<NotificationUser> notificationUser;
}
NotificationUser
public class NotificationUser {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String email;
private String name;
}
I can create events and I can create users. I can also delete events but, I cannot delete users. I get the following message:
update or delete on table "notification_user" violates foreign key constraint "fkjuklqmawfcf1ein89djo7945t" on table "event_notification_user"
Detail: Key (id)=(12) is still referenced from table "event_notification_user"
I don't understand the Annotations to set on the models.
Is there a simple way to handle the relations? I don't want to get my repo locked for some simple stuff like deletions. That's the reason why I use JPARepository.
Thanks for your time.

Hibernate: Repeated Column in Mapping

So in this example scenario I have an attendance DTO, and a worker DTO, workers in this context are separated by department, and a worker can only ever be inside of one department. It is important to note that Worker {id='123-123-123', department='a'} is different to Worker {id='123-123-123', department='b'}, despite them both sharing the same Id.
I have the following class setup to try and separate functions by id and department
public class IdAndDepartmentPK implements Serializable {
private String id;
private String department;
public IdAndDepartmentPK() {}
...
}
This key class is shared between DTOs that require both the Worker's id and department, below are the two DTOs that are causing a problem.
#Entity
#IdClass(IdAndDepartmentPK.class)
public class AttendencetDto {
#Id private String id; // This is a departmentally unique attendenceId
#Id private String department;
#Column private String workerId;
#JoinColumns({
#JoinColumn(name = "workerId"),
#JoinColumn(name = "department")
})
#ManyToOne(fetch = FetchType.EAGER)
private WorkerDto workerDto;
....
}
#Entity
#IdClass(IdAndDepartmentPK.class)
public class WorkerDto {
#Id
private String id;
#Id
private String department;
...
}
WorkerDto does not need to have knowledge of AttendencetDto, but AttendencetDto, does need to have access to WorkerDto and the other data it contains.
Hibernate complains that fields like workerId should be mapped with insert="false" update="false", but if I was to do this then I wouldn't be able to persist those values to the database.
I essentially want to have those fields available whilst also having the WorkerDto available, is this possible?
You should remove #Column private String workerId; because you already map it by relation to WorkerDto.
If you want to create relation between that you should use setWorkerDto method in your AttendencetDto and just save. After transaction ends you will have your relation in DB.

JPA one to many relationship - #transactional - get children collection

I want to get the children collection of the owner entity of a one to many relationship.
I have those two entities :
#Entity
#Table(name = "commande")
public class Commande implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "name")
private String name;
#OneToMany(mappedBy = "commande")
#JoinColumn(name= "papa_id")
#JsonIgnore
private Set<Piece> pieces = new HashSet<>();
#Entity
#Table(name = "piece")
public class Piece implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "ref")
private String ref;
#ManyToOne
private Commande commande;
And the resource :
#RequestMapping(value = "/papas/{id}",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
#Transactional
public ResponseEntity<Papa> getPapa(#PathVariable Long id) {
log.debug("REST request to get Papa : {}", id);
Papa papa = papaRepository.findOne(id);
papa.getEnfants().size();
...
}
I had to put #Transactional in order to make the .size() work (otherwise I have an exception).
It works.
But if in another method I delete one Enfant entity, then if I call getPapa again, I am getting an error durint .size() :
Unable to find com.myapp.stagiaireproject.domain.Enfant with id 3
Is it a problem of a transaction not closed?
For the first time, move all work with repository to service and mark this method as #Transactional. Set #Transactional annotation to controller method is bad practice.
One-to-many annotation is lazy by default, you can explicity set #OneToMany(mappedBy = "commande", fetch = FetchType.EAGER)
to told hibernate to read collection from database when fetching this entity.
Returning to you question: if you done this is one transaction, hibernate uses fist level cache (wich is not disabled), i.e. it caches entities, which loads by PK (id) during the transaction. And if you moves all work with repository to service class, your transaction commited before you return data from controller, and next request will read data from database, not from cache.

JPA OneToMany insert not setting the id's correctly

I have two entities, let's say
Person.java:
#Entity
public class Person implements Serializable {
#Id
#GeneratedValue(strategy = AUTO)
private long id;
#OneToMany(mappedBy = "personData", cascade = CascadeType.PERSIST)
private List<SkillsData> skillsData;
// ...
}
SkillsData.java
#Entity
#Table(name = "SkillsData")
public class SkillsData implements Serializable {
#Id
#GeneratedValue(strategy = AUTO)
private long id;
#JoinColumn(name = "PERSONID")
#ManyToOne(cascade = REMOVE)
private Person personData;
// ...
}
When I create a person, add a list of type SkillsData to it's skillsData field and persist it everything works with no exceptions thrown, but when I browse the database directly in the SkillsData table the field PERSONID is not populated and because of that the skills added can't be referenced to the right person.
I'm trying to fix this problem for quite some time and I'll be thankful for any help.
The problem might be in the fact that you're not setting SkillsData.personData before persisting leaving it null.
You must set it cause adding SkillsData to the Person.skillsData list is not enough since you declared this side of relationship as inverse(mappedBy attribute).
Therefore it is the SkillsData.personData non-inverse side who is responsible for establishing this relationship.

JPA (EclipseLink) persit one-to-many relationship without Cascade.PERSIST

I have two entities.
Sports:
#Entity
public class Sports implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "SPORT_NAME")
private String name;
...
}
and SportFacility:
#Entity
public class SportFacility implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "SPORTFAC_NAME")
private String name;
#OneToMany
private List<Sports> sports;
....
}
Then I have some created sports in Sports table, for example:
--id-----name-----
- 0 - Football -
- 1 - Basketball-
- 2 - Golf -
------------------
And I need to create sport facility with some sports.Lets take all sports
List<Sports> listSports = sb.getAllSports(); //JPQL: SELECT s FROM Sports s
SportFacility sportFacility = new SportFacility("Stadium", listSports);
em.getTransaction().begin();
em.persist(sportFacility);
em.getTransaction().commit();
Error:
java.lang.IllegalStateException: During synchronization a new object was found through a relationship that was not marked cascade PERSIST: database.entities.sports[ id=0 ].
I don' want to use Cascade.ALL or PERSIST becase there are only few sports in table and I always don't need to create new record with same sport...
Thank you.
The exception is related to the fact that collection of Sports that you retrieved are no longer in the persistence context when you try to persist the SportFacility - persistence context is by default transaction scoped (created when transaction begins and destroyed when it ends) - and EL doesn't know what to do with objects it doesn't control.
Move
em.getTransaction().begin();
to the beginning.
What does,
sb.getAllSports();
do? Does it use the same EntityManager, or a different one?
database.entities.sports[ id=0 ]
The error seems to indicate that one of your sports has a 0 id, this seems very odd? Did you persist the sports correctly?

Categories