Spring mvc, hibernate LazyInitializationException when converting entity to dto - java

Why I am getting this error? This is the portion of my daoImpl Im calling
#Transactional
#Repository
public class PersonDaoImpl implements PersonDao{
#Autowired
private SessionFactory sessionFactory;
#SuppressWarnings("unchecked")
#Override
#Transactional(readOnly=true)
public List<Person> getAllPersons(){
List<Person> persons = (List<Person>) sessionFactory.getCurrentSession()
.createCriteria(Person.class)
.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
.list();
return persons;
}
Portion of my person model
#OneToMany(fetch = FetchType.LAZY, mappedBy = "person", cascade = CascadeType.ALL)
private Set<Contact> contacts;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "PERSON_ROLE", joinColumns = {
#JoinColumn(name = "person_id", nullable = false, updatable = false) },
inverseJoinColumns = { #JoinColumn(name = "role_id",
nullable = false, updatable = false) })
private Set<Role> roles = new HashSet<Role>(0);
In my service impl, I convert model to dto using BeanUtils
What am I doing wrong?

My feeling is that in a time when you try to convert the entity to dto using BeanUtils the entity is already detached (e.g. outside persistence context/hibernate session). In your Person class you have a Set<Contact> of contacts which is loaded lazily - that is why it fails.
If Contact does not contain many relations you might change to FetchType.EAGER or you can convert entity while Person is still attached.

In the BeanUtils, you need to initialize the objects via Hibernate as follows:
MyProfile pf = null;
try {
session.beginTransaction();
Query query = session.createQuery("from MyProfile as term where term.profileId=:pId ");
query.setString("pId", pid);
pf = (MyProfile)query.uniqueResult();
if(pf != null)
{
Hibernate.initialize(pf);
}
} catch (HibernateException he) {
throw he;
}
Using Hibenrate.initialize(pf) will initialize the objects contained inside MyProfile object.

Related

Hibernate filter doesn't work

I use Hibernate and I want to filter entities with the Hibernate filter options. But the filter will be ignored. The Workspace entity include a user entity. And i want all workspace entitys with only thise user with doesent have a NULL-Value in the E-Mail field in the database.
I look forward to hearing from you. Thanks
Workspace
#Entity
#Table(name = "WORKSPACEENTITY", schema = "pwdmanager")
#PrimaryKeyJoinColumn(name = "workspace_id", referencedColumnName = "id")
#Setter
#Getter
#FilterDef(name = "FILTER")
public class DBWorkspaceEntity{
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "wkse_space")
private List<DBPasswordEntity> pwde_password;
#OneToOne(fetch = FetchType.EAGER)
#Filters({
#Filter(name="FILTER", condition="{u}.usre_email is not null", aliases={#SqlFragmentAlias(alias="u", entity=DBUserEntity.class)}),
})
private DBUserEntity usre_user;
}
User
#Entity
#Table(name = "USERENTITY", schema = "pwdmanager")
#Setter
#Getter
#PrimaryKeyJoinColumn(name = "user_id", referencedColumnName = "id")
public class DBUserEntity{
#Basic
#Column(name = "USRE_EMAIL", nullable = true, length = 1024)
private String usre_email;
}
Hibernate
public class MasterDao{
private Session session;
private Transaction transaction;
private SessionFactory sessionFactory;
public void prepare() {
sessionFactory = HibernateUtil.getSessionFactory();
this.session = sessionFactory.openSession();
}
public void filter(final DBUserEntity usr) {
try {
session.enableFilter("FILTER");
Query query = session.createQuery("FROM " + DBWorkspaceEntity.class.getSimpleName());
List<DBWorkspaceEntity> result = query.list();
session.disableFilter("FILTER_USER");
} catch (final HibernateException ex) {
log.error(ex);
}
}
}
I think, usre_email in filter condition should be column name.
USRE_EMAIL

Specific deep level size to load association in hibernate

Recently I created a project and in my models I have ManyToMany back references.
My model is like below:
#Entity
public class A {
#ManyToMany(mappedBy = "parents", fetch = FetchType.EAGER)
private Set<A> children = new HashSet<>();
#ManyToMany
#JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
#JoinTable(
name = "link_a_recursion",
joinColumns = #JoinColumn(name = "child_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "parent_id", referencedColumnName = "id")
)
private Set<A> parents = new HashSet<>();
//I removed the rest ( setter, getter and other fields )
}
When I fetch this model and I want to load children it throws StackOverFlowException error ( Recursive exception )
I want to know is there any way to say to hibernate just load one level of associate and don't go deep.
For clarify:
A.children[0].children[0].children should be null to stop recursion
I want to load the first children not all the children inside of the other children
Edited:
I add another entity:
#Entity
public class B {
#OneToMany(mappedBy = "b")
private Set<A> entities = new HashSet<>();
//setter, getter
}
and add below to A entity:
#ManyToOne
private B b;
then I changed below:
#ManyToMany(mappedBy = "parents", fetch = FetchType.EAGER)
to
#ManyToMany(mappedBy = "parents", fetch = FetchType.LAZY)
and in my BService my findOne function is like below:
#Transactional(readOnly = true)
public B findOne(Long id) {
B b = repository.findOne(id);
for (A a: b.getEntities()) {
a.getChildren().size();
}
return b;
}
but again I'm getting error :(
Try lazy fetch instead
#ManyToMany(mappedBy = "parents", fetch = FetchType.LAZY)

Eclipselink merge does not insert a new row in many-to-many relationship

I have a many-to-many relationship between user and role entities. when I try to merge a role by adding new user objects to that, after merging i expect a new row in the joined table (in sql server database) to be inserted but nothing happens.
I guess the problem is the direction of the relationship which the owner is User entity now and should be switched to Role. But if I change it then my spring security wont work. Is there any other way to solve this? except changing many-to-many sides?
Thanks in advance.
User class
#ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinTable(
name = "SEC_USER_ROLE",
joinColumns = {
#JoinColumn(name = "SEC_USER_ID", referencedColumnName = "SEC_USERS")},
inverseJoinColumns = {
#JoinColumn(name = "SEC_ROLE_ID", referencedColumnName = "SEC_ROLES")})
private List<Role> roles;
--
Role class
#ManyToMany(mappedBy = "roles", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private List<User> users;
And here is my merge function
#Override
#Transactional(readOnly = false, propagation = Propagation.REQUIRED)
public T merge(T o) {
o = em.merge(o);
em.flush();
return o;
}

Hibernate/Jpa OneToMany not retrieving data properly

I have an entity class named User which contains this OneToMany column for database:
#Setter
#OneToMany(cascade = CascadeType.ALL, mappedBy = "user")
#JoinTable(
name = "USER_CARS",
joinColumns = #JoinColumn(name="USER_ID", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name="CAR_ID", referencedColumnName = "id")
)
private List<Car> cars;
When I'm inserting an user into database, everything works fine, and his cars are also added in user_cars table. When retrieving the cars i get this exception:
Method threw 'org.hibernate.LazyInitializationException' exception.
I've searched for other answers but didn't found how to solve it. This is how I'm trying to retrieve the User.
public T findById(Long id) {
em = emf.createEntityManager();
em.getTransaction().begin();
T et = (T) em.find(entityClass, id);
em.getTransaction().commit();
em.close();
return et;
}
What is the problem and how can I fix it? I can't understand what's going on in background.
Based on the exception message, it seems that you are retrieving the content of the List cars but the EntityManager session is already closed. Rather than the default lazy initialization for the collection you could use
#OneToMany(cascade = CascadeType.ALL, mappedBy = "user", fetch = FetchType.EAGER)

Hibernate: ID of entity added to list

I am using Spring Data JPA + Hibernate. I need to get ID of entity after it's added to a list of other entity and saved. Here is the code:
#Entity
public class Product extends AbstractAuditable<Long> {
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "product_id", nullable = false)
private List<Feedback> feedbacks = new ArrayList<Feedback>();
...
}
#Entity
public class Feedback extends AbstractPersistable<Long> {
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "product_id", insertable = false, updatable = false, nullable = false)
private Product product;
...
}
public interface ProductRepository extends JpaRepository<Product, Long> {
}
Feedback feedback = new Feedback();
product.getFeedbacks().add(feedback);
productRepository.saveProduct(product);
feedback.getId(); // returns null
How to correctly get ID of feedback after it's saved?
You can execute refresh method from Hibernate Session interface (or EntityManager interface) to "re-read the state from the given instance from the underlying database". Example:
session.save(object);
session.flush();
session.refresh(object);
You can find more information here:
Hibernate calling get() after save() on the newly created record within the same transaction
Hibernate: Refresh, Evict, Replicate and Flush
Hibernate calling get() after save() on the newly created record within the same transaction
Force refresh of collection JPA entityManager

Categories