LazyInitializationException with map collection - java

I know that it is a trite question, but I could not find a solution. I have two beans and one of them has HashMap collection. I'm getting an exception when trying to read this collection. Mapping config had been specified to load this collection eagerly.
My environment is :
Hibernate 4.2.0
mysql-connector-java 5.1.24
Also I have two beans:
public class FeaturedDoc {
private Long id;
private Map<Feature, Float> features;
public FeaturedDoc() {
features = new HashMap<Feature, Float>();
}
(getters and setters)
}
and
public class Feature {
private Long id;
private String name;
private Long internalId;
(getters and setters)
}
This beans have mapping:
<class name="Feature" table="FEATURE">
<id name="id" type="long" column="ID">
<generator class="increment"/>
</id>
<property name="name" length="255" type="string" unique="true" column="NAME" index="INDEX_NAME"/>
<property name="internalId" type="long" unique="true" not-null="false" column="INTERNAL_ID" index="INDEX_INTID"/>
<sql-insert>insert into FEATURE (NAME, INTERNAL_ID, ID) values (?, ?, ?) on duplicate key update ID = ID</sql-insert>
</class>
<class name="FeaturedDoc" table="FEATURED_DOC">
<id name="id" type="long" column="ID">
<generator class="increment"/>
</id>
<map name="features" table="DOC_FEATURE" cascade="all" lazy="false" fetch="join">
<key column="ID"></key>
<map-key-many-to-many column="FEATURE_ID" class="Feature"/>
<element column="value" type="float"/>
</map>
</class>
Also I have DAO layer with method:
public FeaturedDoc read(long id) {
FeaturedDoc fd = null;
try {
session.beginTransaction();
fd = session.get(FeaturedDoc.class, id);
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
} finally {
close();
}
return fd;
}
When I'm trying to do something like this:
FeaturedDoc fd = daoService.read(26);
System.out.println(fd.getFeatures());
I'm getting an exception
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
Do you know how should I fix this error?

Assuming that everything else is okay (in the mappings), have you tried putting lazy="false" before cascade="all". I found that this was a problem in my mapping which resulted in this LazyInitializationException error.
This ordering is shown in the following Hibernate Reference: http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/collections.html

I have solved this problem! The reason was in Feature class. It had not hashCode and equals functions. After implementation of these functions everything has become ok.

Related

Hibernate Criteria API where clause in many to many relation

I have relation many to many with extra fileds in linking table(mapping in xml files). Using criteria api how to add restrictions to name of product?
public class Recipe implements Serializable{
private int id_re;
private String name;
private Set<ProductRecipe> listOfRecipe_Product = new HashSet<>(0);
}
public class ProductRecipe implements Serializable{
private ProductRecipeMapping id;
private float quantity;
}
public class ProductRecipeMapping implements Serializable{
private Product product;
private Recipe recipe;
}
public class Product implements Serializable{
private int id_p;
private String name;
}
Mapping:
<class entity-name="recipe" name="Recipe" table="recipe">
<id name="id_re" type="java.lang.Integer">
<column name="id_re" />
<generator class="identity" />
</id>
<set name="listOfRecipe_Product" table="recipe_product" lazy="false" fetch="select" cascade="all">
<key>
<column name="id_re" not-null="true" />
</key>
<one-to-many entity-name="productRecipe" />
</set>
</class>
<class entity-name="productRecipe" name="ProductRecipe" table="recipe_product">
<composite-id name="id" class="ProductRecipeMapping" >
<key-many-to-one name="recipe" entity-name="recipe" column="id_re" />
<key-many-to-one name="product" entity-name="product" column="id_p" />
</composite-id>
<property name="quantity" type="float" column="quantity" />
</class>
<class entity-name="product" name="Product" table="product">
<id name="id_p" type="java.lang.Integer" column="id_p">
<generator class="identity" />
</id>
<property name="name" column="name" type="java.lang.String" not-null="true" length="255"/>
</class>
E.G. I use criteria for get recipe with name test:
Criteria cr = session.createCriteria(Recipe.class);
cr.add(Restrictions.eq("name", "test"));
but I don't know to get all recipes with list name of products
something like cr.add(Restrictions.eq("product.name", "test")); (but not work)
I use 2 idea to resolve this problem but nothing work:
1) Restrictions.eq("listOfRecipe_Product.id.product.name", "test")
but i get error org.hibernate.QueryException: could not resolve property: listOfRecipe_Product.id.product.name of: recipe
2)
cr.createCriteria("listOfRecipe_Product")
.createCriteria("id")
.createCriteria("product")
.add(Restrictions.eq("name", "test"));
I get error org.hibernate.QueryException: Criteria objects cannot be created directly on components. Create a criteria on owning entity and use a dotted property to access component property: listOfRecipe_Product.id
You will need to create aliases in order to add constraints to mapped entities;
e.g.:
Criteria cr = session.createCriteria(Recipe.class)
.createAlias("listOfRecipe_Product", "listOfRecipe_Product")
.createAlias("listOfRecipe_Product.id", "id")
.createAlias("id.product", "product")
.add(Restrictions.eq("product.name", "test"));

Hibernate criteria specific query

I have such entity:
public class LogEntity implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private Date changeTime;
private Set<Integer> changes;
//getters and setters
}
And its mapping:
<hibernate-mapping>
<class name="com.myproject.dao.LogEntity" table="LOG">
<id name="id" column="ID" type="integer">
<generator class="native" />
</id>
<property name="changeTime" column="CHANGE_TIME" type="timestamp"/>
<set name="changes" table="LOG_CHANGES" lazy="false" cascade="all" order-by="CHANGE_ID">
<key column="ID"/>
<element column="CHANGE_ID" type="integer"/>
</set>
</class>
The problem is how to check that Set<Integer> changes contains given parameter using hibernate criteria. I can't createAlias() for this and also try to use sqlRestriction() but get something ugly.
I am pretty sure that there is some easy way but I just cant see it. Thanks for any help.

org.hibernate.NonUniqueObjectException when saving a list of child objects

I need to save several child objects when creating the parent object. Ideally, I want to save them in one transaction, however, I keep getting an org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session.
In this example, a SubDiscipline has many SubdisciplinePlayers.
I feel that there's something wrong with the mapping
POJOs:
Subdiscipline.java
public class Subdiscipline {
private int id;
private int disciplineId;
private String name;
private List<SubdisciplinePlayer> subdisciplinePlayers;
public Subdiscipline() {
}
//standard constructors, getter & setters...
}
SubdisciplinePlayers.java
public class SubdisciplinePlayer implements Serializable {
private int idPlayers;
private int disciplineId;
private int subDisciplineId;
private int players;
private int minPlayers;
private int maxPlayers;
private Subdiscipline subdiscipline;
public SubdisciplinePlayer() {
}
//standard constructors, getter & setters...
}
Main.java:
public class Main {
#SuppressWarnings("unchecked")
public static void main(String[] args) {
SessionFactory sf = HibernateUtil.getSessionFactory();
Session session = sf.openSession();
session.beginTransaction();
Subdiscipline sd = new Subdiscipline("soccer_" + (new Date()).getTime(), new Date(), new Date(), new Status(1) );
sd.setDisciplineId(4);
session.save(sd);
SubdisciplinePlayer sdp = new SubdisciplinePlayer();
sdp.setDisciplineId(sd.getDisciplineId());
sdp.setSubDisciplineId(sd.getId());
sdp.setSubdiscipline(sd);
sdp.setIdPlayers(555);
SubdisciplinePlayer sdp2 = new SubdisciplinePlayer();
sdp2.setDisciplineId(sd.getDisciplineId());
sdp2.setSubDisciplineId(sd.getId());
sdp2.setSubdiscipline(sd);
sdp2.setIdPlayers(457);
sd.setSubdisciplinePlayers(new ArrayList<SubdisciplinePlayer>());
sd.getSubdisciplinePlayers().add(sdp);
sd.getSubdisciplinePlayers().add(sdp2);
session.save(sd);
session.getTransaction().commit();
session.close();
}
}
Mappings
Subdiscipline Mapping
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="net.viralpatel.hibernate.Subdiscipline" table="sub_discipline">
<id name="id" column="sub_dis_id" unsaved-value="0">
<generator class="increment"/>
</id>
<property name="disciplineId" column="dis_id" type="int"/>
<property name="name" column="sub_discipline" type="string"/>
<bag name="subdisciplinePlayers" table="sdis_players" inverse="true" cascade="all">
<key column="sub_dis_id" />
<one-to-many class="net.viralpatel.hibernate.SubdisciplinePlayer" />
</bag>
</class>
</hibernate-mapping>
SubdisciplinePlayer Mapping
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="net.viralpatel.hibernate.SubdisciplinePlayer" table="sdis_players">
<composite-id>
<key-property name="disciplineId" column="dis_id" type="int"/>
<key-property name="subDisciplineId" column="sub_dis_id" type="int" />
</composite-id>
<property name="idPlayers" column="id_players" type="int"/>
<property name="players" column="players" type="int"/>
<property name="minPlayers" column="min_players" type="int"/>
<property name="maxPlayers" column="max_players" type="int"/>
<many-to-one name="subdiscipline" class="net.viralpatel.hibernate.Subdiscipline" cascade="none" insert="false" update="false">
<column name="sub_dis_id"/>
</many-to-one>
</class>
</hibernate-mapping>
Exception thrown
Exception in thread "main" org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [net.viralpatel.hibernate.SubdisciplinePlayer#net.viralpatel.hibernate.SubdisciplinePlayer#1cd7e9c3]
You have declared composite key with fields disciplineId & subDisciplineId for your entity SubdisciplinePlayer.
Now in your program you are creating 2 instances of SubdisciplinePlayer with same composite id.
SubdisciplinePlayer sdp = new SubdisciplinePlayer();
sdp.setDisciplineId(sd.getDisciplineId());
sdp.setSubDisciplineId(sd.getId());
SubdisciplinePlayer sdp2 = new SubdisciplinePlayer();
sdp2.setDisciplineId(sd.getDisciplineId());
sdp2.setSubDisciplineId(sd.getId());
So when you call Session.save(sd), hibernate observed that you are trying to save 2 instances of SubdisciplinePlayer and throwing the exception as :
org.hibernate.NonUniqueObjectException: a different objectwith the same identifier
value was already associated with the session:
[net.viralpatel.hibernate.SubdisciplinePlayer#
net.viralpatel.hibernate.SubdisciplinePlayer#1cd7e9c3]
To fix the issue just make sure that the composite id of SubdisciplinePlayer should have different values as primary key should be unique.
Please use merge instead of save when you are trying with second time save.
sd.setSubdisciplinePlayers(new ArrayList<SubdisciplinePlayer>());
sd.getSubdisciplinePlayers().add(sdp);
sd.getSubdisciplinePlayers().add(sdp2);
session.merge(sd);
I listed out more ref for you.
Ref 1
Ref 2

How to save parent with children?

I have parent entity Order with child entity OrderItem. I want to save object Order together with Set<OrderItem>, but idOrder is auto increment. Between Order and OrderItem is one-to-many relationship. OrderItem include reference to parent Order. So Order item must be saved firstly and then must be saved OrderItem with assigned idOrder.
Here is Order.hbm.xml
<class name="hibernate.Order" table="order" catalog="my">
<id name="idOrder" type="java.lang.Integer">
<column name="id_order" />
<generator class="identity" />
</id>
<set name="orderItems" inverse="true" cascade="all">
<key>
<column name="id_order" not-null="true" />
</key>
<one-to-many class="hibernate.OrderItem" />
</set>
</class>
class Order
public class Order implements java.io.Serializable {
private Integer idOrder;
private Set<OrderItem> orderItems = new HashSet<OrderItem>(0);
}
Here is OrderItem.hbm.xml
<class name="hibernate.OrderItem" table="order_item" catalog="my">
<id name="idOrderItem" type="java.lang.Integer">
<column name="id_order_item" />
<generator class="identity" />
</id>
<many-to-one name="order" class="hibernate.Order" fetch="select">
<column name="id_order" not-null="true" />
</many-to-one>
</class>
class OrderItem
public class OrderItem implements java.io.Serializable {
private Integer idOrderItem;
private Order order;
}
When I try save it, it throw me exception.
object references an unsaved transient instance - save the transient instance before flushing: hibernate.Order
EDIT:
It works with following statement. Is this correct?
Order order = mapper.map(dtoOrder, Order.class);
Set<OrderItem> orderItems = order.getOrderItems();
for (OrderItem orderItem : orderItems) {
orderItem.setOrder(order);
}
order.setOrderItems(orderItems);
session.save(order);
so basically there are 3 workarounds here.
1.Save Order rather than OrderItem, because regarding to your current hibernate configuration the cascading navigates from Order to OrderItem;
2.have a cascade=save-update in OrderItem.hbm.xml , and then saving an OrderItem will automatically save Order; but this is not recommented ;
3.for some reason,if you insist to save OrderItem and don't want to change your hibernate confiuraion, I'm afraid you have to explicitly save Order first and then invoke session.flush() to get Order instance persistent before saving OrderItem;
I hope this make sense.

Hibernate One-to-many HashMap not updating on child

I have the following parent object which maps to a table in my database:
public Parent {
private Long id;
private String mid;
private Integer days;
private BigDecimal fee;
private DateTime createdDate = new DateTime();
private DateTime lastModifiedDate;
private Map<String, Child> children;
}
With the following .hbm.xml:
<hibernate-mapping default-access="field">
<class name="Parent" table="parent_table">
<id column="id" length="50" name="id" unsaved-value="null">
<generator class="increment"/>
</id>
<property length="50" name="mid"/>
<property name="days"/>
<property name="fee"/>
<property name="createdDate" type="(...)PersistentDateTime"/>
<property name="lastModifiedDate" type="(...)PersistentDateTime"/>
<map cascade="all-delete-orphan" inverse="true" name="children" >
<key column="parentId" />
<map-key column="country" type="string" />
<one-to-many class="Child" />
</map>
</class>
</hibernate-mapping>
The child object is as follows:
public class Child implements Serializable {
private Long parentId;
private String country;
private String cu;
}
With the following .hbm.xml:
<hibernate-mapping default-access="field">
<class name="Child" table="child_table">
<composite-id>
<key-property name="parentId"/>
<key-property name="country"/>
<key-property name="cu"/>
</composite-id>
</class>
</hibernate-mapping>
After acquiring a Parent object from my db via:
getSession().createCriteria(Parent.class)
.add(Restrictions.eq("mid", mid))
.uniqueResult();
After making some changes to Child.cu in the children map I call a saveOrUpdate on the Parent object. After doing so all appears to save / update fine but upon checking the child_table in the db, these changes have not been saved / updated.
I believe this has something to do with the mappings of the map in the Parent class but can't seem to figure it out. Any help would be appreciated.
Thanks in advance.
If I understand correctly, you're modifying a field which is part of the primary key of your entity. This is illegal: the ID should be immutable.
My advice is to follow the good practices: use a non-composite, purely technical, auto-generated primary key. Everything will be much simpler (and also faster).

Categories