lazy="false" not working in hibernate 4.3.x - java

I am trying to test the functioning of lazy loading in hibernate with the following code.
Query query = session.createQuery("From Publishers as publisher where publisher.publisherName <= :name");
query.setString("name", "penguin");
Publishers publisher = (Publishers)query.iterate().next();
Set<Books> booksByPublisher = new HashSet<>();
booksByPublisher = publisher.getBooks();
session.close();
System.out.println(publisher.getPublisherName());
for(Books book : booksByPublisher) {
System.out.println(book);
}
mapping for publishers and books classes are as following, respectively:
<class name="newapplication.domain.Publishers" table="PUBLISHERS" >
<id name="publisherId" type="integer" column="PUBLISHER_ID"/>
<property name="publisherName" type="string" column="PUBLISHER_NAME"/>
<set name="books" table="BOOKS_PUBLISHERS" inverse="true" fetch="join" lazy="false">
<key column="publisher"/>
<many-to-many class="newapplication.domain.Books" column="book" />
</set>
</class>
<class name="newapplication.domain.Books" table="BOOKS" >
<id name="bookId" type="integer" column="BOOK_ID">
<generator class="sequence">
<param name="sequence">BOOKIDSEQUENCE</param>
</generator>
</id>
<property name="bookName" type="string" column="NAME"/>
<many-to-one name="author" class="newapplication.domain.Authors" column="AUTHOR"/>
<many-to-one name="cover" class="newapplication.domain.Covers" column="COVER"/>
<set name="publishers" table="BOOKS_PUBLISHERS" lazy="false">
<key column="BOOK"/>
<many-to-many class="newapplication.domain.Publishers" column="PUBLISHER"/>
</set>
</class>
Despite having set lazy="false" loading in the publisher class i get the following error.
Exception in thread "main" org.hibernate.LazyInitializationException: could not initialize proxy - no Session
What is wrong here? Shouldn't the Set be loaded as soon as the database is hit for the publishers' object?

Your many-to-one associations in Books are lazy; that's where the exception comes from.
By default, all associations are lazy when using Hibernate native mappings, as opposed to JPA standard (when using JPA-style mappings) where to-one associations are eager by default.

Related

'Repeated column in mapping' when mapping a class to an existing list of objects

I'm adding ResourcePermission to the object Report. Each Query object can have in a one-to-one relationship. A Query extends Resource and has ResourcePermission's in a one-to-many (one Query to many Permissions).
I need to add the same property to the Report object associated with the Query because it can have different permissions. When I add the list and the map the one Query to many Permission relationship I get
Caused by: org.hibernate.MappingException: Repeated column in mapping for entity: com.bio.ResourcePermission column: resource_id (should be mapped with insert="false" update="false")
Which I am not understanding why, the Report does not extend Query or Resource and therefore it isn't mapped twice. Can a table just not be the many for multiple one-to-many relationships?
<class name="com.bio.Report" table="REPORT">
<id name="id" type="long" column="id">
<generator class="foreign">
<param name="property">query</param>
</generator>
</id>
<property name="name" column="name"/>
<!--Trying to add this list mapping breaks it-->
<bag name="permissions" table="RESOURCE_PERMISSION">
<key column="resource_id" not-null="true"/>
<one-to-many class="com.bio.ResourcePermission"/>
</bag>
<!-- This query extends Resource-->
<one-to-one name="query" class="com.bio.Query" />
</class>
This is the original item that had ResourcePermissions
<class name="com.bio.Resource" table="RESOURCE">
<id name="id" type="long" column="id">
<generator class="native">
<param name="sequence">SEQ_RESOURCE_AUTO</param>
</generator>
</id>
<bag name="permissions" table="RESOURCE_PERMISSION" lazy="true" batch-size="50" cascade="all-delete-orphan">
<key column="resource_id" not-null="true"/>
<one-to-many class="com.bio.ResourcePermission"/>
</bag>
</class>
The Permission mapping
<class name="com.bio.ResourcePermission" table="RESOURCE_PERMISSION">
<id name="id" type="long" column="id">
<generator class="native">
<param name="sequence">SEQ_RES_PERM_AUTO</param>
</generator>
</id>
<property name="canEdit" column="edit"/>
<property name="canView" column="can_view"/>
<property name="canRun" column="run"/>
<property name="everyone" column="everyone"/>
</class>
I had to set inverse="true" on the Report mapping since the ReportPermission will be responsible for the relationship.
<bag name="permissions" table="RESOURCE_PERMISSION" inverse="true">
<key column="resource_id" not-null="true"/>
<one-to-many class="com.bio.ResourcePermission"/>
</bag>

How to make hibernate unidirectional many-to-many association updateable?

I have two entities - Category and Attribute. Category can have multiple related attributes, and Attribute can be related to any number of categories. Association should be available only on Category side - Attribute objects are not aware of categories they are related to.
So I model this association as unidirectional many-to-many:
Category.hbm.xml
<class name="Category" table="category" proxy="ICategory" entity-name="category">
<id name="id" column="id" unsaved-value="null"><generator class="identity" /></id>
...some properties...
<bag name="relatedAttributes" table="category_attribute" fetch="select">
<key column="id_category" />
<many-to-many column="id_attribute" entity-name="attribute" />
</bag>
</class>
and Attribute.hbm.xml
<class name="Attribute" table="attribute" proxy="IAttribute" entity-name="attribute">
<id name="id" column="id" unsaved-value="null" ><generator class="identity" /></id>
...some properties...
</class>
Mapping works perfectly with current data until it needs an update. I just want to do things as simple as these:
ICategory c = (ICategory) session.get("category", 1);
c.getRelatedAttributes().add((IAttribute) session.get("attribute", 2));
session.update("category", c);
How can i make this association updateable?
Finally done. Changes that affect behavior:
<bag name="relatedAttributes" table="category_attribute" fetch="select" inverse="false" cascade="save-update">
...
</bag>
and do not forget to call session.flush() after operations.

hibernate narrow down lazy loaded collection

I have 2 classes:
public class Car {
private Integer id;
private List<CarOrder> carOrders;
}
public class CarOrder {
private Car car;
private Long endDate;
private Long id;
}
and hibernate mapping
<class entity-name="car" name="test.es.Car" table="CARS" schema="ARK_ES">
<cache usage="read-write"/>
<id name="id" column="ID">
<generator class="sequence">
<param name="sequence">ES_SEQUENCE</param>
</generator>
</id>
<bag name="carOrders" inverse="true" lazy="true">
<cache usage="read-write"/>
<key column="CAR_ID"/>
<one-to-many not-found="ignore" entity-name="carOrder"/>
</bag>
</class>
<class entity-name="carOrder" name="temp.es.CarOrder" table="CAR_ORDERS" schema="ARK_ES">
<cache usage="read-write"/>
<id name="id" column="ID">
<generator class="sequence">
<param name="sequence">ES_ORDER_SEQUENCE</param>
</generator>
</id>
<property name="endDate" column="END_DATE"/>
<many-to-one name="car" entity-name="car">
<column name="CAR_ID"/>
</many-to-one>
</class>
I need to load all cars and car orders with endDate greater than some value. Also i need to cache the query for car order. i tried to use hibernate filters, but they are not cached. Is it possible to achieve this using hibernate api without custom queries?
I forgot to mention that car can have no orders, but it must be in result.
Thanks.
So you can use the #fitler and #filterdef annotation on your collection class. But then it is very important to enable the filters in the session. Please follow this link on how to enable filters, they are not enabled by default.
How to enable hibernate filter for sessionFactory.getCurrentSession()?

Making join with Criteria

I'm terribly new to Hibernate. I've googled for two hours but I still can't figure out, how to make JOIN without using HQL, only by criteria. I have tables Clients(cID, name) and Visits(vID, vcID, date). The relation is one to many (one client can visit multiple times). I would also like to do it without setFetchMode. Just Criteria. Do I have to change the mappping xml?
UPDATE:
this is part of my mapping xml:
<class name="Client" table="Clients">
<id name="cID" column="cID"><generator class="native"/></id>
<property name="name" length="10" not-null="true"/>
</class>
<class name="Visit" table="Visits">
<id name="vID" column="vID"><generator class="native"/></id>
<property name="vcID" length="10" not-null="true"/>
<property name="date" length="25" not-null="true"/>
</class>
Having a class Client with a list-attribute "visits" that's mapping to your Visit-Entity:
Criteria criteria = session.createCriteria(Client.class);
criteria.addCriteria("visits");
This would create an inner join between your client-table and your visits-table.
Update:
Here you'll find some good examples: http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/querycriteria.html#querycriteria-associations
Mapping Example
I hardly ever use hibernate mapping xml, however it should read similiar to:
<class name="Client" table="Clients">
<id name="cID" column="cID"><generator class="native"/></id>
<property name="name" length="10" not-null="true"/>
<bag name="visits">
<key column="vcId"/>
<one-to-many class="Visit"/>
</bag>
</class>
Tell Hibernate that there is a property "visits" which represents a one-to-many relationship.
You need to update you mapping:
<class name="Client" table="Clients">
<id name="cID" column="cID"><generator class="native"/></id>
<property name="name" length="10" not-null="true"/>
<!-- Declare Set<Visit> visits in the Client class-->
<set name="visits" lazy="false" cascade="all">
<key column="vcID"/>
<one-to-many class="your.package.Visit"/>
</set>
</class>
<class name="Visit" table="Visits">
<id name="vID" column="vID"><generator class="native"/></id>
<!-- and add "Client client" property to your Visit class -->
<many-to-one name="client" column="vcID" lazy="false"/>
<property name="date" length="25" not-null="true"/>
</class>
Then:
Criteria criteria = session.createCriteria(Visit.class).addCriteria("client")
.add(Restriction.eq(...));
or
Criteria criteria = session.createCriteria(Client.class).addCriteria("visits")
.add(Restriction.eq(...));
And Hibernate will join them automatically.

Hibernate saveOrUpdate() doesn't seem to cascade creation and saving

I'm new to Hibernate and am trying to save a "UserState" with a list of "WorkspaceState"s. UserState objects are keyed by a username that is set, the WorkspaceStates are set by UUID scheme. My issue is that if I have a UserState with one WorkspaceState in it, the UserState gets saved but the WorkspaceState does not.
Here are the Hibernate mapping
<hibernate-mapping>
<class name="UserState" table="USERSTATE">
<id name="owner" type="java.lang.String">
<column name="OWNER" />
<generator class="assigned" />
</id>
<list name="workspaces" inverse="false" cascade="all" table="WORKSPACESTATE" lazy="true">
<key>
<column name="UID" />
</key>
<list-index></list-index>
<one-to-many class="WorkspaceState" />
</list>
</class>
</hibernate-mapping>
<hibernate-mapping>
<class name="WorkspaceState" table="WORKSPACESTATE">
<id name="uid" type="java.lang.String">
<column name="UID" />
<generator class="uuid" />
</id>
<property name="owner" type="java.lang.String">
<column name="OWNER" />
</property>
</class>
</hibernate-mapping>
I have a UserState object with one WorkspaceState in it. When I do a session.saveOrUpdate(userst), I see that hibernate has already removed the WorkspaceState from my userst object. Then the commit saves it to the DB without the workspacestate in it.
In truth the WorkspaceState themselves have lists, but I suspect whatever I'm doing wrong continues onward.
Thanks
Edit - how it's committed. HibernateUtil is as it appears in the standard hibernate document examples:
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction transaction = null;
try {
transaction = session.beginTransaction();
String username = (String) session.merge(state);
transaction.commit();
} catch (HibernateException e) {
transaction.rollback();
e.printStackTrace();
return false;
} finally {
session.close();
}
you need to change cascade reference to save-update and remove inverse attribute from workspace list mapping

Categories

Resources