Can I change Lazy propety value of createSQLQuery at runtime? - java

I wanna set lazy to "false" but only to one method at in runtime.
Can I do?
this.getSession().createSQLQuery("select * from customers....")....
Attention: im using createSQLQuery not createCriteria.
CustomerMapping.xml here:
<hibernate-mapping>
<class name="com.example.entities.customers.Customer"
table="CUSTOMERS">
<id name="id" type="long">
<column name="ID" />
<generator class="sequence">
<param name="sequence">seq_customers</param>
</generator>
</id>
<property name="name" type="String">
<column name="NAME_C" />
</property>
<many-to-one name="address"
class="com.example.entities.Address" fetch="select"
cascade="all">
<column name="ADDRESS_ID" />
</many-to-one>
</class>
</hibernate-mapping>
I wanna set lazy to false for Address.
I have to do this because this method return a list of customers (with address) and when I iterate this list and print its very slow cause the lazy is setted true (by default).

Is there a reason you are using SQL instead of HQL? I would stay away from SQL statements when using hibernate when possible.
I would implement it like this in HQL:
from Customer c
join fetch c.address
the join fetch makes Customers address no longer lazy.

Related

Hibernate One-to-One foreign key using xml Not deleting orphan

I have two classes A and B.
<id name="id" type="java.lang.Integer" column="A_ID">
<generator class="identity" />
</id>
<property name="name" column="NAME"/>
<many-to-one name="B" cascade="all"
column="B_ID" unique="true"/>
</class>
<id name="id" type="java.lang.Integer" column="B">
<generator class="identity" />
</id>
<property name="n" column="N"/>
</class>
A.setB(new B());
When I save it works fine.
when I remove the record. A.setB(null);
I see a orphan record.
I see in A Table the column for B is null but on B Table there is still a record.
I tried to look in other solutions but couldnot find the ans to this.

Hibernate: dynamic join multiple tables

I'm new to Hibernate and I'm trying to dynamically join more table. I have built an example with three tables: Employee, Address, Country. I want to retrieve all employees of a certain country. Here my config file:
<class entity-name="Employee">
<id name="id" type="int" column="id">
<generator class="native"/>
</id>
<property name="firstName" column="first_name" type="string"/>
<property name="lastName" column="last_name" type="string"/>
<property name="salary" column="salary" type="int"/>
<many-to-one name="address" column="address" unique="true"
class="Address" not-null="true"/>
</class>
<class entity-name="Address">
<id name="id" type="int" column="id">
<generator class="native"/>
</id>
<property name="street" column="street_name" type="string"/>
<property name="city" column="city_name" type="string"/>
<property name="state" column="state_name" type="string"/>
<property name="zipcode" column="zipcode" type="string"/>
<many-to-one name="country" column="country" unique="true"
class="Country" not-null="true"/>
</class>
<class entity-name="Country">
<id name="id" type="int" column="id">
<generator class="native"/>
</id>
<property name="name" column="name" type="string"/>
<property name="code" column="code" type="string"/>
</class>
If I do
List employees = session.createCriteria("Employee")
.createCriteria("address")
.createCriteria("country")
.add(Restrictions.eq("code","IT"))
.list();
I get the right result back but my goal is not to manually specify the whole path between start table and filter table: I want that hibernate makes the job for me. I would like to write something like this:
List employees = session.createCriteria("Employee")
.createCriteria("country")
.add(Restrictions.eq("code","IT"))
.list();
but I get the error message
org.hibernate.QueryException: could not resolve property: country of: Employee
Hibernate is just a wrapper or abstraction layer to hide away SQL expressions.
In your working example Hibernate builds a SQL select statement creating a double JOIN and returning the desired output. You are feeding Hibernate with the "knowledge" of how to filter the associated table. The same as you would write your own SQL statement.
But in you second example you expect Hibernate to guess a second level association from the first table. Hibernate simply looks up if table Employee has a column/foreign key country and it fails to find it. So the error is: could not resolve property: country of: Employee
You can not expect from Hibernate to do this kind of magic as it would produce or sorts of false queries.
Just to illustrate on your example.
In case your Employee would have two fields of type Address:
<class entity-name="Employee">
<id name="id" type="int" column="id">
<generator class="native"/>
</id>
<property name="firstName" column="first_name" type="string"/>
<property name="lastName" column="last_name" type="string"/>
<property name="salary" column="salary" type="int"/>
<many-to-one name="bussiness_address" column="bussiness_address" unique="true"
class="Address" not-null="true"/>
<many-to-one name="home_address" column="home_address" unique="true"
class="Address" not-null="true"/>
</class>
Both would have a Country linked ... what should in case of this query hibernate do?
List employees = session.createCriteria("Employee")
.createCriteria("country")
.add(Restrictions.eq("code","IT"))
.list();
Filter country by the home or the business address or both?
Or just imagine a case where you do filtering by an id field present in every table.
So to wrap things up: Hibernate can't do magic it is only here to hide away raw SQL.
If I translate your query to Java language, what you are trying to do is getting value of coutry directly out of employee. In Java you would get a compile error though. Such thing automatically does not work neither in Java, nor in Hibernate or plain SQL. There is no direct link between employee and country, but there is a sequence of links employee -> address -> country.
To fix this in Java way, one could maitain a secondary reference to country directly from employee. Then calling employee.getAddress().getCountry() and employee.getCountry() would be equal.
To achieve this in hibernate, you would need to add new field country to Employee and map it as a non-modifiable many-to-many relationship with entity Country, using entity Address to map the relationship. This would only reduce 2 hibernate joins to one, it could not be applied recurrently to more than 2 joins.
If this solution is OK for you, I can provide you with example syntax.

Hibernate: NonUniqueObjectException while insert

Trying to insert a new Entity using hibernate and it is throwing me this exception:
a different object with the same identifier value was already associated with the session
I understand that this error is coming because hibernate finds a similar object in the memory. But I am creating a new object every time before inserting. Does it have anything to do with sequence?
hbm
<class name="MyObject" table="My_Object">
<id column="object_id" name="id" type="long">
<generator class="sequence">
<param name="sequence">OBJ_SEQ</param>
</generator>
</id>
<property name="column1" column="column_1" type="string" not-null="true"/>
<property name="column2" column="column_2" type="string" not-null="true"/>
<property name="column3" column="column_3" not-null="true" type="string"/>
</class>
The problem is when you are trying to persist an entity, a entity with the same id is already present in the database. Reason for this can be, you are manually assigning a value to the id, or you have reset the OBJ_SEQ in database.

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.

Querying Composite Key inner Entity properties

I have one entity called ProductTemplate with the following hibernate mapping
<hibernate-mapping default-cascade="none">
<class name="com.stackoverflow.ProductTemplateImpl" table="PRODUCT_TEMPLATE" dynamic-insert="false" dynamic-update="false">
<composite-id name="productTemplatePk" class="com.stackoverflow.product.ProductTemplatePK">
<key-property name="templateType" type="java.lang.String">
<column name="TEMPLATE_ID" sql-type="VARCHAR2(255)" not-null="true"/>
</key-property>
<key-many-to-one name="product" class="com.stackoverflow.ProductImpl" >
<column name="PROD_ID"/>
</key-many-to-one>
</composite-id>
</class>
</hibernate-mapping>
where ProductTemplatePK is a normal java Primary key class.
and another entity called Product with the following hibernate mapping:
<hibernate-mapping default-cascade="none">
<class name="com.stackoverflow.ProductImpl" table="PRODUCT" dynamic-insert="false" dynamic-update="false">
<id name="id" type="java.lang.String" unsaved-value="null">
<column name="PROD_ID" sql-type="VARCHAR2(255)"/>
<generator class="assigned">
</generator>
</id>
<property name="state" type="java.lang.String">
<column name="PROD_STATE" not-null="true" unique="false"/>
</property>
<property name="nameEn" type="java.lang.String">
<column name="PROD_NAME_EN" not-null="true" unique="false"/>
</property>
</class>
</hibernate-mapping>
Now if I tried to retrieve all productTemplates based on the productId I can do it using the following hibernate criteria:
Criteria productTemplateCriteria = this.getSession().createCriteria(ProductTemplate.class);
productTemplateCriteria.add(Restrictions.in("productTemplatePk.product.id", "1"));
but I don't know how to retrieve those templates based on the product.nameEn as the following code:
Criteria productTemplateCriteria = this.getSession().createCriteria(ProductTemplate.class);
productTemplateCriteria.add(Restrictions.in("productTemplatePk.product.nameEn", "Ali"));
generates the following error:
Caused by: org.hibernate.QueryException: could not resolve property: productTemplatePk.product.nameEn of: com.stackoverflow.ProductTemplateImpl.
so how can I query an entity property that is mapped as part of a composite primary key ?
I manged to solve this by simple HQL query as I didn't find any way to do it using hibernate API
this is the HQL query I used:
from com.stackoverflow.ProductTemplateImpl productTemplate
where productTemplate.productTemplatePk.product.state not in (:productStates)
But I'm still interested to know if there is any Hibernate API combination that can do it.
I was not able to get deeper than 2 levels except for ids when specifying property names in criteria. Try using explicit join with alias:
Criteria crit = this.getSession().createCriteria(ProductTemplate.class);
crit.addAlias("productTemplatePk.product","p")
.add(Restrictions.in("p.nameEn", "Ali"));

Categories

Resources