detached entity passed to persist: A class with ManyToOne relation to 2 more classes - jpa

Comment class
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "user_id")
private User user;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "image_id")
private Image image;
User class
#OneToMany(mappedBy = "user", cascade = CascadeType.MERGE, fetch =
FetchType.EAGER)
private List<Comment> comments = new ArrayList<>();
Image class
#OneToMany(mappedBy = "image",cascade = CascadeType.MERGE,fetch =
FetchType.EAGER)
private List<Comment> comments = new ArrayList<Comment>();
These are the ManyToOne and OneToMany relations I have. I am unable to persist the Comment object due to "detached entity passed to persist: ImageHoster.model.Comment" error.

I kind of figured out the issue. In the CommentRepository class where I am persisting the Comment object, I used .merge instead of .persist
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
try{
transaction.begin();
em.merge(newComment);
instead of em.persist(newComment);

Related

Bidirectional #OneToOne persistence

I am starting with JPA and EclipseLink and did some experiments. But results are a little unexpected for my understanding. Here for example I have a bidirectional relation between two entities:
#Entity
#Table(name = "student")
public class Student {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
#OneToOne(mappedBy = "student", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
private Tuition tuition;
#Entity
#Table(name = "tuition")
public class Tuition {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Long fee;
// Que columna en la tabla Tuition tiene la FK
#JoinColumn(name = "student_id")
#OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private Student student;
I have created two tests to check persisting both entities from both sides. When I try to persist from one side it works OK, both entities are persisted. But when trying to do the same from the other side Student in Tuition have a null value
Here are the tests:
#FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class Jpa1to1Bidireccional {
private static final String PERSISTENCE_UNIT_NAME = "JPA_PU";
private EntityManagerFactory factory;
#Before
public void init() throws Exception {
factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
}
#Test
public void testCase_1() {
System.out.println("Testcase_1 executes");
EntityManager em = factory.createEntityManager();
// Begin a new local transaction so that we can persist a new entity
em.getTransaction().begin();
Student s = new Student();
s.setName("Pirulo");
Tuition t = new Tuition();
t.setFee(2134L);
s.setTuition(t);
em.persist(s);
// Commit the transaction, which will cause the entity to // be stored in the
// database
em.getTransaction().commit();
em.close();
}
#Test
public void testCase_2() {
System.out.println("Testcase_2 executes");
EntityManager em = factory.createEntityManager();
em.getTransaction().begin();
Student s = new Student();
s.setName("Cachilo");
Tuition t = new Tuition();
t.setFee(3134L);
t.setStudent(s);
em.persist(t);
em.getTransaction().commit();
em.close();
}
Any help to understand what is going on, will be very welcomed.
Regards,
In your first case you are persisting student and then cascading a save to tuition but tuition has no student. You need to keep bidirectional relationships in sync before persisting
Second case you persist tuition and it requires fk of student so it cascade persist student first

Using Named Entity Graphs in Eclipselink not work

I have 2 classes
Collections
#Entity
#NamedEntityGraph(
name = "cars-graph",
attributeNodes = #NamedAttributeNode("cars"))
public class Collections {
#Id
#ReturnInsert(returnOnly=true)
private Long id;
#ManyToMany(cascade = ALL)
#JoinTable(name="CarsCollections",
joinColumns= #JoinColumn(name="COLLECTIONS_ID", referencedColumnName="ID"),
inverseJoinColumns=
{#JoinColumn(name = "MODELSRANGE_ID", referencedColumnName = "MODELSRANGE_ID"),
#JoinColumn(name = "MODELS_ID", referencedColumnName = "MODELS_ID"),
#JoinColumn(name = "TYPES_ID", referencedColumnName = "TYPES_ID")
}
)
public List<Cars> cars;
and Cars
#Entity(name = "Cars")
public class Cars {
#EmbeddedId
private CarsId id;
#ManyToOne(fetch = FetchType.EAGER)
#MapsId("modelsRangeid")
#JoinColumn(name = "MODELSRANGE_ID")
private ModelsRange modelsrange;
#ManyToOne(fetch = FetchType.EAGER)
#MapsId("modelsid")
#JoinColumn(name = "MODELS_ID")
private Models models;
#ManyToOne(fetch = FetchType.EAGER)
#MapsId("typesid")
#JoinColumn(name = "TYPES_ID")
private Types types;
#ManyToOne(cascade = CascadeType.PERSIST, fetch = FetchType.EAGER)
#JoinColumn(name = "MAKE")
private Makes makes;
When i try to get Collections with Cars
EntityGraph entityGraph = em.getEntityGraph("cars-graph");
Collections collections = em.createQuery("select r from Collections r where r.id = :id", Collections.class)
.setParameter("id", 1L)
.setHint("javax.persistence.fetchgraph", entityGraph)
.getSingleResult();
System.out.println(collections.getCars());
I get {IndirectList: not instantiated}. Does not give errors, but Cars does not load.
If you add to the Collections entity for the Cars field "EAGER"
...
#ManyToMany(cascade = ALL, fetch = FetchType.EAGER)
#JoinTable(name="CarsCollections",
...
It works.
But then Cars will always load.
I use Jakarta EE9 and Eclipselink
Problem in javax name. In Jakarta EE need to use:
...
.setHint("jakarta.persistence.loadgraph", entityGraph)
...

LazyInitializationException could not initialize proxy - no Session

My problem is that I'm getting LazyInitializationException.
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:148) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:266) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:73) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at sk.kristian.dienes.eshop.entity.SubCategory_$$_jvsta89_5.hashCode(SubCategory_$$_jvsta89_5.java) ~[main/:na]
at sk.kristian.dienes.eshop.entity.Product.hashCode(Product.java:18) ~[main/:na]
I have two #ManyToOne relationships in one class
public class Product implements Serializable{
#Id
#Column(name = "id")
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id_category")
private Category category;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id_sub_category")
private SubCategory subCategory;
}
#Entity
#Data
public class SubCategory implements Serializable {
#OneToMany(mappedBy = "subCategory", cascade = CascadeType.ALL,fetch = FetchType.EAGER)
private List<Product> products;
}
#Entity
#Data
public class Category implements Serializable {
#OneToMany(mappedBy = "category", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private List<Product> products;}
I'm using HttpSession.
I've also tried to add this property spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true but It did not helped. I would like to know if there is any solution. Also tried to use Transactional anotation in services.
The problem is you try to call object that is detached.
For example)
Product product = em.find(Product.class, id)
// somewhere `em.detach(product)` is called.
product.getCategory(); // It raises Exception
I don't know what you try with those objects. But you should reattach entity to EntityManager like em.merge(detachedObject)
Check state of EntityManager
https://vladmihalcea.com/a-beginners-guide-to-jpahibernate-entity-state-transitions/

JPA potential Sync Issue

In my lodger class, i have
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "lodger", orphanRemoval=true)
// #JsonBackReference
private List<RoomPayment> roomPaymentList;
In my RoomPayment class i have
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "lodger_id")
private Lodger lodger;
Actually i do
#Override
public Long save(RoomPaymentDto roomPaymentDto) {
RoomPayment roomPayment;
if (roomPaymentDto.getRoomPaymentId() != null) {
roomPayment = repository.findOne(roomPaymentDto.getRoomPaymentId());
} else {
roomPayment = new RoomPayment();
}
MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
mapperFactory.classMap(RoomPayment.class, RoomPaymentDto.class).byDefault().register();
MapperFacade mapper = mapperFactory.getMapperFacade();
mapper.map(roomPaymentDto, roomPayment);
repository.save(roomPayment);
return roomPayment.getRoomPayementId();
}
In this method, do i need to get the Lodger and assign it to roomPayment?
No, if the dto contains the right Lodger of course.
The point is that there are no cascades from RoomPayment to the associated Lodger, meaning that Hibernate will not complain about the detached object when you save the roomPayment.
Hibernate will just take the id from the lodger instance which it will use to maintain the association (because RoomPayment is the owner of the association).

Entity Object Not Getting Persisted: New object was found through a relationship that was not marked

I am trying to persist the following entity:
public class CommentEntity {
#Id
#ManyToOne(optional=false,cascade=CascadeType.REFRESH, targetEntity=UserEntity.class)
#JoinColumn(name="USERID",referencedColumnName="USERID")
private UserEntity userEntity;
#ManyToOne(optional=false,cascade=CascadeType.REFRESH, targetEntity=PostEntity.class)
#JoinColumn(name="POSTID",referencedColumnName="POSTID")
private PostEntity postEntity;
}
But the error comes out:
During synchronization a new object was found through a relationship that was not marked cascade PERSIST: entity.PostEntity#16afec.
when I try to persist PostEntity, it is persisted. No such exception is thrown:
public class PostEntity {
#ManyToOne(optional = false, cascade = CascadeType.REFRESH, fetch = FetchType.LAZY, targetEntity = UserEntity.class)
#JoinColumn(name = "USERID", referencedColumnName = "USERID")
private UserEntity userEntity;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "postEntity", fetch = FetchType.LAZY)
private List<CommentEntity> commentEntityList;
}
Why it is happening? UserEntity is:
public class UserEntity {
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "userEntity")
private List<PostEntity> postEntityList;
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "userEntity")
private List<CommentEntity> commentEntityList;
}
I am persisting commentEntity using the code:
entityManagerFactory = Persistence
.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
entityManager = entityManagerFactory.createEntityManager();
entityTransaction = entityManager.getTransaction();
entityTransaction.begin();
entityManager.persist(commentEntity);
entityTransaction.commit();
entityManager.close();
I am not able to understand what can be the cause? And then why PostEntity is getting persisted in the same situation?
I am using EclipseLink
Because you try to persist CommentEntity that have either userEntity or postEntity (or both) referencing to the entity that is not persisted. Call to em.persist(instance of commentEntity) does not cause those entities to be persisted, because you cascaded only refresh. You should persist those entities with separate calls to em.persist.
If this does not answer to your question, please provide the code that creates entities and persists them.