Get entries in intersection table based on key - java

I have three tables:
offers; offer_groups; offer_group_members.
The offers and offer_groups tables are mapped with hibernate (see below).
In offer_group_members, I store to which group the offers belong (offer primary key, offer group primary key).
I am kinda new to hibernate so my question is: How can I get all the OfferGroups from the OFFER_GROUP_MEMBERS table based on the Offer key?
I tried something like this:
Criteria crit;
crit = getSession().createCriteria(Offer.class);
crit = crit.createCriteria("offerGroups");
crit.add(eq("key", offerKey));
Here are the mappings:
for offer:
<composite-id name="comp_id"
class="com.infonova.psm.hibernate.prodsrv.OfferPK">
<key-property name="key" column="KEY"
type="java.lang.String" length="128">
</key-property>
</composite-id>
for offer_group_key:
<id name="key" type="java.lang.String" column="KEY" length="128">
<generator class="assigned"/>
</id>`
for offer_group_key:
<set name="offers" table="OFFER_GROUP_MEMBERS" lazy="true" inverse="false"
cascade="none">
<key>
<column name="OFFER_GROUP_KEY"/>
</key>
<many-to-many class="Offer">
<column name="OFFER_KEY"/>
</many-to-many>
</set>
for offer:
<set name="offerGroups" table="OFFER_GROUP_MEMBERS"
inverse="true" lazy="true" cascade="none">
<key>
<column name="OFFER_KEY" />
</key>
<many-to-many
class="OfferGroup">
<column name="OFFER_GROUP_KEY" />
</many-to-many>
</set>

It would be easier if you showed us the entities, since it's on them that HQL and criteria queries work.
Anyway, in HQL:
select og from Offer o
inner join o.offerGroups og
where o.key = :key
And in Criteria, unfortunately, IIRC, all you can do is select the root entity or scalars, so it's hard to do this without having a bidirectionall association. If you had a bidirectional association, you could do
Criteria c = session.createCriteria(OfferGroup.class, "og");
c.createAlias("og.offers", "o");
c.add(Restrictions.eq("o.key", key));
Since you don't have the bidirectional association, the only way that I know of is to do this:
Criteria c = session.createCriteria(OfferGroup.class, "og");
DetachedCriteria dc = DetachedCriteria.forClass(Offer.class, "o");
dc.createAlias("o.offerGroups", "og2");
dc.add(Restrictions.eq("o.key", key));
dc.setProjection(Projections.property("og2.id"));
c.add(Subqueries.propertyIn("og.id", dc));
which corresponds to this ugly HQL query:
select og from OggerGroup og
where og.id in (select og2.id from Offer o
inner join o.offerGroups og2
where o.key = :key)
For such simple static queries, I don't see any reason to go with Criteria rather than HQL.

Related

How to access joined-subclass's properties in HQL?

Consider the following hibernate mapping (using hibernate 4):
Answer with a DataCollection joined-subclass:
<hibernate-mapping>
<class name="Answer" table="answer">
<many-to-one name="answeredForm" class="AnsweredForm" fetch="select">
<column name="answered_form_id" />
</many-to-one>
<joined-subclass table="data_collection" name="DataCollection" extends="Answer">
<key column="id"></key>
</joined-subclass>
</class>
</hibernate-mapping>
AnsweredForm with a PatientForm joined-subclass:
<hibernate-mapping>
<class name="AnsweredForm" table="answered_form">
<joined-subclass table="patientForm" name="PatientForm" extends="AnsweredForm">
<many-to-one name="patient" class="Patient" fetch="join">
<column name="patient_id" />
</many-to-one>
</joined-subclass>
</class>
</hibernate-mapping>
Question: Using HQL, how can you ask for "all datcollections whose AnsweredForm belongs to patient x"?
SELECT answer FROM DataCollection answer
JOIN answeredForm answeredForm
WHERE answer.answeredForm.patient.code=:patientCode
This HQL yields the error:
ERROR: missing FROM-clause entry for table "answeredfo2_2_"
And rightly so, as the SQL translation of this query is:
SELECT datacollec0_.id AS id1_62_,
datacollec0_1_.free_text AS free_tex2_62_
FROM data_collection datacollec0_
INNER JOIN answer datacollec0_1_
ON datacollec0_.id = datacollec0_1_.id
CROSS JOIN answered_form answeredfo1_
CROSS JOIN answered_form answeredfo2_
CROSS JOIN patient patient3_
WHERE datacollec0_1_.answered_form_id = answeredfo1_.id
AND datacollec0_1_.answered_form_id = answeredfo2_.id
AND answeredfo2_2_.patient_id = patient3_.id
AND CASE
WHEN answeredfo1_4_.id IS NOT NULL THEN 4
WHEN answeredfo1_1_.id IS NOT NULL THEN 1
WHEN answeredfo1_2_.id IS NOT NULL THEN 2
WHEN answeredfo1_3_.id IS NOT NULL THEN 3
WHEN answeredfo1_.id IS NOT NULL THEN 0
END = 2
AND patient3_.code = ?
Try to use the following hql:
SELECT a FROM Answer a
JOIN a.answeredForm af
WHERE af.patient.code=:patientCode
Look at this part of the hibernate documentation for additional explanations and examples.

Hibernate Criteria do not add schema to table

I have three tables device , vehicle and vehicle_device all tables are in one schema 'tcm' and I'm trying to get 'vehicle' by 'device imei' . In Vehicle.class i have field 'Set devices' and create maping:
Vehicle.hbm.xml
<hibernate-mapping package="hibernate.entity">
<class name="Vehicle" table="vehicles" schema="tcm">
<id name="id" type="integer" column="id">
<generator class="sequence">
<param name="sequence">tcm.vehicles_id_seq</param>
</generator>
</id>
.
.
.
<set name="devices" table="vehicle_device"
inverse="false" lazy="true" fetch="select" cascade="all" >
<key>
<column name="vehicle_id" not-null="true" />
</key>
<many-to-many entity-name="hibernate.entity.Device">
<column name="device_id" not-null="true" />
</many-to-many>
</set>
</class>
when execute criteria to take the results for needed 'device imei'
#Override
public Vehicle getVehicleByDeviceImei(String imei) {
Criteria criteria = getSession().createCriteria(Vehicle.class);
criteria.createAlias("devices", "devices").add(Restrictions.eq("devices.imei", imei));
Vehicle v = (Vehicle) criteria.uniqueResult();
return v;
}
Everything is OK except that the query that is generated does not add schema 'tcm' for the link table 'vehicle_device' in first inner join
select .
.
.
.
from
tcm.vehicles this_
inner join
vehicle_device devices3_
on this_.id=devices3_.vehicle_id
inner join
devices devices1_
on devices3_.device_id=devices1_.id
where
devices1_.device_imei=?
and have an error :
ERROR: relation "vehicle_device" does not exist
LINE 17: vehicle_device devices3_
If i add manual schema to generated query --> 'tcm.vehicle_device' it work.
how to fix my configuration so Hibernate Criteria adds the schema for table 'vehicle_device'.
I fix problem. I just added scheme = 'tcm' in set tag in mapping

Hibernate-Foreign key object Null on Select Query

I have two tables ex:User and Role. with many-to-one relation between User and Role (one User can contain many Roles)
I used SQL query to insert the data in to the User table with the role_id(assume pk of Role table) as foreign key.
Now,when I tried to fetch the records of User with a particular role.
i am using following code to fetch the User object.
User user=(User)session.get('User.class',user_id);
Role role=user.getRole();
On executing the above lines,some times I'm getting the User Object,some times not.
The relation mapping between the objects is as below.
<many-to-one name="role" class="com.example.Role" fetch="select">
<column name="role_id" precision="14" scale="0" />
</many-to-one>
<set name="user" cascade="delete" table="User" >
<key>
<column name="role_id" not-null="true" />
</key>
<one-to-many class="com.example.User" />
</set>
Is there any way to prevent it occuring?
Is this possible that some times the select query will give me output and sometimes null.
There seem to be a fundamental mistake in your design. You stated that one User can contain Many Roles. This means foreign key (which points the PK of User) should be in Roles. But you seem to have put the foreign key in User.
Aside from DUKE answer who clearly pointed that your mapping says that a Role has many users as opposed to your requirement, there are still some issues with your code:
First you need to add inverse="true" to your one-to-many side. Since you have a bi-directional association, only one side can own the relationship:
<set name="user" cascade="delete" table="User" inverse="true">
<key>
<column name="role_id" not-null="true" />
</key>
<one-to-many class="com.example.User" />
</set>
And then it's much more efficient to fetch the Role in the same query with the User:
User user = (User)
session.createQuery(
"select u from User left join fetch u.role where u.id = :user_id')
.setParameter("user_id", user_id)
.uniqueResult();

inner join in hibernate

I am just a beginner in Hibernate, I would like to execute this query but I don't know how .. any help please?
SELECT DISTINCT agents.username
FROM users u
INNER JOIN UserDistributors ud
ON u.id = ud.[user]
INNER JOIN users agents
ON agents.type =9
INNER JOIN UserDistributors agentsdistributor
ON agentsdistributor.distributor = ud.distributor
AND agents.id=agentsdistributor.[user]
WHERE u.id=1778
my user.hbm file has one to many relation to distributor
<set name="userDistributors" table="UserDistributors"
inverse="true" lazy="true" fetch="select">
<key>
<column name="[user]" not-null="true" />
</key>
<one-to-many class="net.tedata.dp.model.UserDistributors" />
</set>
Try this
Criteria c = session.createCriteria(User.class);
c.createAlias("ud", "UserDistributors"); // inner join by default
c.add(Restrictions.eq("ud.id", "<Name>"));

Hibernate Mapping of Join Table with Meta Data

I'm trying to figure out how to map the relationship between two tables through a join table that has some meta data in it. In short, the three tables represent the page of a form, and each page can contain any number of elements (questions.) For some reason, the original developer decided that elements could be used on multiple forms. This means that the weight column, used to order the elements on the page, is in the join table.
How the heck do I map this in XML? (Annotations aren't an option.)
For the join table, I guess it's like this:
<class name="com.foo.bar.model.db.ApplicationPageElements"
table="APPLICATION_PAGE_ELEMENTS">
<composite-id name="id" class="com.foo.bar.model.db.ApplicationPageElementsKey">
<key-property name="pageId" column="page_id"/>
<key-property name="elementId" column="element_id"/>
</composite-id>
<property name="weight" type="java.lang.Long">
<column name="WEIGHT" precision="0" />
</property>
</class>
My instincts have me wanting to do something like this from the ApplicationPage side of things:
<set name="applicationElements" table="applicationPageElement">
<key column="page_id"/>
<many-to-many column="element_id" unique="true"
class="com.foo.bar.model.db.ApplicationElements" />
</set>
And that's where I get all slack-jawed, stare at the screen, and sob.
We're using .hbm.xml files to map our database. We also made the decision to not change our database.
Any ideas on how to map this in XML?
Instead of thinking of the relationship between application_page and application_element as many to many, think of it as a one to many relationship from application_page to ApplicationPageElements and a one to many relationship from application_element to ApplicationPageElements.
In your application_page xml mapping add this:
<set name="applicationElements" inverse="true">
<key column="page_id"/>
<one-to-many class="ApplicationPageElements"/>
</set>
page_id forms a part of the primary key of the join table. So, mark the collection as inverse.
Your mapping for the join table is correct. But, with the above change current mapping of your join table you can navigate from application_page to ApplicationPageElements. To navigate from application_page to application_element (via ApplicationPageElements) add a many to one relationship in join table mapping.
<class name="com.foo.bar.model.db.ApplicationPageElements"
table="APPLICATION_PAGE_ELEMENTS">
<composite-id name="id" class="com.foo.bar.model.db.ApplicationPageElementsKey">
<key-property name="pageId" column="page_id"/>
<key-property name="elementId" column="element_id"/>
</composite-id>
<property name="weight" type="java.lang.Long">
<column name="WEIGHT" precision="0" />
</property>
<many-to-one name="elements" class="ApplicationElements"
column="element_id" not-null="true" insert="false" update="false"/>
<many-to-one name="page" class="ApplicationPage"
column="page_id" not-null="true" insert="false" update="false"/>
</class>
Note that in the above many-to-one mapping, insert and update attributes are set to false. This is necessary because the columns are mapped twice, once in the composite key (which is responsible for insertion of the values) and again for the many-to-one associations.
The above use case is mentioned in detail in the book: Java Persistence with Hibernate.

Categories