Order By <collection element's property> in many-to-many association - java

I have three tables. Order, Location, Order_Location where Order_Location is table that holds many-to-many relation.
Order has List<Location>. Location has property called city. Using HQL (Hibernate 3.6 for Java), I want to get all the locations for a particular order, ordered by the city.
In hbm file, List<Location> is mapped using idbag. Though I got the HQL, the generated SQL query is having join to Location and Order_Location table twice which I feel is overhead.
What am I doing wrong here?
SELECT o.locationList FROM Order o
join o.locationList locList
where o.orderId = 1
order by locList.city desc
which translates to something like below
select
order4_.LOC_ID as order1_355_,
order4_.LOC_CODE as order2_355_,
order4_.CITY as order3_355_,
order4_.CITY_LONG_NAME as order4_355_
from
sche.order order0_
inner join
sche.order_location order1_
on order0_.ORDER_ID=order1_.ORDER_ID
inner join
sche.location order2_
on order1_.LOC_ID=order2_.LOC_ID
inner join
sche.order_location order3_
on order0_.ORDER_ID=order3_.ORDER_ID
inner join
sche.location order4_
on order3_.LOC_ID=order4_.LOC_ID
where
order0_.ORDER_ID=1
order by
order2_.city desc
========= EDIT
Order.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"
>
<hibernate-mapping>
<class name="collectionorderby.Order" table="ORDER">
<id name="orderId" type="string">
<column name="ORDER_ID" length="32" />
<generator class="uuid" />
</id>
<idbag name="locationList" lazy="false" table="ORDER_LOCATION" fetch="select">
<collection-id column="ORDER_LOCATION_ID" type="string">
<generator class="uuid" />
</collection-id>
<key>
<column name="ORDER_ID" length="32" not-null="true" />
</key>
<many-to-many column="LOC_ID" class="collectionorderby.Location"
fetch="join" />
</idbag>
</class>
</hibernate-mapping>
Location.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
<hibernate-mapping>
<class name="collectionorderby.Location" table="LOCATION">
<id name="locId" type="string">
<column name="LOC_ID" length="50" />
</id>
<property name="locCode" type="string">
<column name="LOC_CODE" length="50" />
</property>
<property name="city" type="string">
<column name="CITY" length="50" />
</property>
<property name="cityLongName" type="string">
<column name="CITY_LONG_NAME" length="500" />
</property>
</class>
</hibernate-mapping>
==== EDIT
Noticed that when we provide order by, translated query gets the select from first instance of table where as the order by is done using the second instance of the table. This will not happen, I suppose, if we avoid the duplicate instance of these tables.

The following worked as expected. The alias locList was used in select instead of o.locationList
SELECT locList FROM Order o join o.locationList locList where o.orderId = 1 order by locList.city desc

Related

Hibernate query returns list of null

With the following mapping file:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="net.woodenstar.model.shopcenter.GroupItem" table="GROUP_ITEMS">
<id name="id" type="int">
<column name="SHC_GIT_ID" />
<generator class="org.hibernate.id.enhanced.SequenceStyleGenerator">
<param name="sequence_name">GROUP_ITEMS_SEQUENCE</param>
<param name="optimizer">none</param>
<param name="increment_size">1</param>
</generator>
</id>
<property name="name" type="string">
<column name="SHC_GIT_NAME" length="30" unique="false" not-null="true" />
</property>
</class>
the model GroupItem is being saved without any hesitation, but when it comes to:
List<GroupItem> result = query.list();
the result is a list with the members of null. The dbms is mysql.
UPDATE ONE
the query:
from net.woodenstar.model.shopcenter.GroupItem e where 1=1 order by e.id
What you're looking at is the internal structure of an empty ArrayList. Look at the size. It's 0. This is not a list of nulls. It's an empty list. The list is backed by an array, and since the list is empty, all the elements of the backing array are null.
So, the result you get is perfectly normal: the query just didn't find any matching entity.

Mapping two columns to same column in a lookup table using hibernate hbm file

I am working on an application that saves employee data using jsf 1.2, richfaces 3.3, for ORM i am using hibernate 3. I am saving data in 'Employee' basic table about two fields i.e Present City and Permanent City. The City values come from a lookup table 'City' . my hbm file for the employee table has following code:-
<many-to-one name="presentcity" cascade="lock" column="PRESENT_CITY_ID"
class="org.lookups.City" lazy="false">
</many-to-one>
<many-to-one name="permanentcity" cascade="lock" column="PERM_CITY_ID"
class="org.lookups.City" lazy="false">
</many-to-one>
this question did not help as it uses annotations and i need to work with hbm file. The problem is, when i update one of the presentcity or permanentcity, both the values are changed.
structure of my tables is as follows:-
employee table
________________________________________________________
emp_id name age PRESENT_CITY_ID PERM_CITY_ID
________________________________________________________
203 paul 28 3 7
. . . . .
301 ferris 29 6 9
_________________________________________________________
city lookup table
______________________
id city
______________________
3 Chicago
. .
6 Cairo
. .
9 Wales
______________________
The hibernate.cfg.hbm files for both employee and city are as follows:-
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="org.Employee" table="EMP_MAIN">
<id name="empId" type="long" column="EMP_ID">
<generator class="increment"></generator>
</id>
<property name="emp_No" type="long" column="EMP_NO" />
<property name="name" type="string" column="NAME" />
<many-to-one name="presentcity" class="org.lookups.City"
fetch="select" cascade="none">
<column name="PRESENT_CITY_ID" precision="22" scale="0"
not-null="false">
<comment>present city of the employee</comment>
</column>
</many-to-one>
<many-to-one name="permanentcity" class="org.lookups.City"
fetch="select" cascade="none">
<column name="PERM_CITY_ID" precision="22" scale="0"
not-null="false">
<comment>permanent city of the employee</comment>
</column>
</many-to-one>
</class>
</hibernate-mapping>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="org.lookups.City" table="LU_CITY">
<id name="id" type="long" column="CITY_ID">
<generator class="increment"></generator>
</id>
<property name="city" type="string" column="CITY_NAME" />
</class>
</hibernate-mapping>
how to get around this problem.
I've adapted this from a working hbm file that we use at our company so I know it works. It includes the column name for mapping. Maybe that is what you're missing?
<many-to-one name="presentcity" class="org.lookups.City" fetch="select" cascade="none">
<column name="PRESENT_CITY_ID" precision="22" scale="0" not-null="false">
<comment>the present city of the employee</comment>
</column>
</many-to-one>
<many-to-one name="permanentcity" class="org.lookups.City" fetch="select" cascade="none">
<column name="PERM_CITY_ID" precision="22" scale="0" not-null="false">
<comment>the permanent city of the employee</comment>
</column>
</many-to-one>
Good luck.

HQL JOIN QUERY: could not resolve property:

I am getting the following error when I try to execute a join query
("could not resolve property: Countries of: com.fexco.helloworld.web.model.Customer [select cus from com.fexco.helloworld.web.model.Customer as cus join cus.Countries as cou where cus.id = cou.id]")
I am trying to join the Customer and Countries tables together by a common id
Customer.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.ccg.db.test">
<class name="Customer" table="Customer">
<id name="id" column="id" type="bigiint">
<generator class="native"/>
</id>
<property name="firstname" type="string" >
<column name="firstname" />
</property>
<property name="surname" type="string" >
<column name="surname" />
</property>
<property name="address1" type="string" >
<column name="address1" />
</property>
<property name="address2" type="string" >
<column name="address2" />
</property>
<many-to-one name="Countries" column="id" class="Countries" />
</class>
</hibernate-mapping>
Countries.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.ccg.db.test">
<!-- CLASS NAME MIGHT BE CUSTOMER -->
<class name="Countries" table="Countries">
<id name="id" column="id">
<generator class="native" />
</id>
<property name="country" column="country" />
</class>
</hibernate-mapping>
And this is the query that i am trying to call
String sql_query = "select cus from Customer as cus join cus.Countries as cou where cus.id = cou.id";
I am new to HQL so not sure about everything with it yet so does anybody know how to solve this?
Thanks
It's cus.countries, not cus.Countries. Property names are case sensitive.
try
select cus from Customer cus where cus.id = cus.countries.id

Hibernate One-To-Many Could Not Initialise Collection

I have two database tables, User and PageComment. Using Hibernate, I'm trying to store a Set of PageComment objects in the User comment (comments made to that user), by using one-to-many relationship in the hbm XML files.
The problem is, I seem to be able to retrieve the set from a User object, but as soon as I try to access any of the objects stored within the set, or even access on of the methods included in the set class (i.e. size()), the JVM throws "org.hibernate.exception.GenericJDBCException: could not initialize a collection". I'm at a loss on this one.
HBM For User Table:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="User" table="user">
<id name="username" column="Username" type="string">
<generator class="assigned"></generator>
</id>
<property name="password" column="Password" type="string"></property>
<property name="firstname" column="Firstname" type="string"></property>
<property name="surname" column="Surname" type="string"></property>
<property name="email" column="Email" type="string"></property>
<property name="admin" column="Admin" type="integer"></property>
<set name="commentsMadeTo" inverse="true">
<key column="userMadeTo"/>
<one-to-many class="PageComment"/>
</set>
</class>
</hibernate-mapping>
HBM For PageComment:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="PageComment" table="PageComment">
<composite-id>
<key-property name="userMadeBy" column="UserMadeBy" type="string" />
<key-property name="userMadeTo" column="UserMadeTo" type="string" />
<key-property name="time" column="Time" type="integer" />
<generator class="assigned"></generator>
</composite-id>
<property name="commentText" column="CommentText" type="string"></property>
<many-to-one name="userMadeTo" column="Username" not-null="true" class="User" />
</class>
</hibernate-mapping>
I'm trying to test the mapping with this method:
Session session = sessionFactory.openSession();
User theUser = (User)session.createQuery("FROM User WHERE Username='Samat'").uniqueResult();
System.out.println("Trying to print out all comments made to 'Samat'");
Set<PageComment> theComments = theUser.getCommentsMadeTo();
for(PageComment p: theComments){
System.out.println(p.getAllData());
}
I spot that there are some problems in the relationship mapping
HBM For User Table:
<set name="commentsMadeTo" inverse="true">
<key column="XXXXXXXX"/>
<one-to-many class="PageComment"/>
</set>
HBM For PageComment:
<many-to-one name="userMadeTo" column="XXXXXXX" not-null="true" class="User" />
The value XXXXX represents the column name on the "many" side (i.e PageComment table in your case) that associates to its "One" side. It should have the same value in both mapping hbm.
Try to change the hbm for user table to:
<set name="commentsMadeTo" inverse="true">
<key column="Username"/>
<one-to-many class="PageComment"/>
</set>

Hibernate Query Problem

I am using Hibernate. My database is as follows
A Category has many attributes
class category
contains
private Set <Attribute> AllAttributes= new HashSet <Attribute>();
class attribute
How do I retrieve all categories together with their attributes because I am trying 'from category' but it is not working
Category Mapping File:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated Dec 16, 2010 8:37:02 AM by Hibernate Tools 3.4.0.Beta1 -->
<hibernate-mapping>
<class name="com.BiddingSystem.Models.Category" table="CATEGORY">
<id name="CategoryId" type="long">
<column name="CATEGORYID" />
<generator class="native" />
</id>
<property name="CategoryName" type="java.lang.String">
<column name="CATEGORYNAME" />
</property>
<many-to-one name="ParentCategory" class="com.BiddingSystem.Models.Category">
<column name="PARENT_CATEGORY_ID" />
</many-to-one>
<set name="SubCategory" lazy="false" cascade="all-delete-orphan" inverse="true">
<key>
<column name="PARENT_CATEGORY_ID" />
</key>
<one-to-many class="com.BiddingSystem.Models.Category" />
</set>
<set name="AllAttributes" table="ATTRIBUTE" inverse="false" lazy="true" cascade="all">
<key>
<column name="CATEGORYID" />
</key>
<one-to-many class="com.BiddingSystem.Models.Attribute" />
</set>
</class>
</hibernate-mapping>
Attribute Mapping File:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated Dec 16, 2010 5:25:09 AM by Hibernate Tools 3.4.0.Beta1 -->
<hibernate-mapping>
<class name="com.BiddingSystem.Models.Attribute" table="ATTRIBUTE">
<id name="AttributeId" type="long">
<column name="ATTRIBUTEID" />
<generator class="native" />
</id>
<property name="AttributeName" type="java.lang.String">
<column name="ATTRIBUTENAME" />
</property>
<set name="Options" table="ATTRIBUTEOPTION" inverse="false" cascade="all">
<key>
<column name="ATTRIBUTEID" />
</key>
<one-to-many class="com.BiddingSystem.Models.AttributeOption" />
</set>
</class>
</hibernate-mapping>
You have mapped the association with lazy="true". This tells hibernate that by default, a category's attributes should only be loaded from the database when they are actually accessed, in contrast to lazy="false" which would instruct hibernate to load the attributes whenever it loads a category. However, the directive in the mapping file affects all queries.
In case you want it only for a particular query, check out
http://docs.jboss.org/hibernate/core/3.5/reference/en/html/queryhql.html#queryhql-joins :
A "fetch" join allows associations or
collections of values to be
initialized along with their parent
objects using a single select. This is
particularly useful in the case of a
collection. It effectively overrides
the outer join and lazy declarations
of the mapping file for associations
and collections. See Section 20.1,
“Fetching strategies” for more
information.
from Cat as cat
inner join fetch cat.mate
left join fetch cat.kittens
A fetch join does not usually need to
assign an alias, because the
associated objects should not be used
in the where clause (or any other
clause). The associated objects are
also not returned directly in the
query results. Instead, they may be
accessed via the parent object. The
only reason you might need an alias is
if you are recursively join fetching a
further collection:
from Cat as cat
inner join fetch cat.mate
left join fetch cat.kittens child
left join fetch child.kittens
The fetch construct cannot be used in
queries called using iterate() (though
scroll() can be used). Fetch should be
used together with setMaxResults() or
setFirstResult(), as these operations
are based on the result rows which
usually contain duplicates for eager
collection fetching, hence, the number
of rows is not what you would expect.
Fetch should also not be used together
with impromptu with condition. It is
possible to create a cartesian product
by join fetching more than one
collection in a query, so take care in
this case. Join fetching multiple
collection roles can produce
unexpected results for bag mappings,
so user discretion is advised when
formulating queries in this case.
Finally, note that full join fetch and
right join fetch are not meaningful.

Categories

Resources