Hibernate criteria problem with composite key - java

I got this hibernate mapping:
<class name="CoverageTerm" table="coverage_term">
<composite-id name="id" class="CoverageTermPK">
<key-many-to-one name="productTerm" class="ProductTerm">
<column name="termtype_id"></column>
<column name="product_id" ></column>
</key-many-to-one>
<key-many-to-one name="productCoverage" class="ProductCoverage" column="product_coverage_id"></key-many-to-one>
</composite-id>
<property name="data"/>
</class>
This is a simple composite key mapping with a relation to table productCoverage and a composite key relation to productterm.
Now the problem comes in my search function:
public CoverageTerm getCoverageTermFromProductTermCoverage(ProductTerm productTerm, ProductCoverage productCoverage) {
Criteria critCt = getSession().createCriteria(CoverageTerm.class);
Criteria critCtId = critCt.createCriteria("id");
critCtId.add(Restrictions.eq("productTerm", productTerm));
critCtId.add(Restrictions.eq("productCoverage", productCoverage));
return (CoverageTerm) critCt.uniqueResult();
}
This should let me make a subcriteria on "id" (which is the primary key, CoverageTermPK) and add restrictions on it, but when I run it I get the error message:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.hibernate.QueryException: could not resolve property: productTerm of: CoverageTerm
This feels strange, shouldn't it get the CoverageTermPK there? If I try with a subcriteria on the "data" property the criterias work, I just don't seem to be able to get the PK on the "id" subcriteria.
Any ideas as to why this is happening?

Not sure about your specific class structure but try to add id this way instead of separate criteria:
Restrictions.eq("id.productTerm", productTerm);
Restrictions.eq("id.productCoverage", productCoverage);

Related

Hibernate Criteria with composite-id - could not resolve property

I'm using Hibernate 4.3.2.Final and in the mapping.xml, I have a composite id like this:
<class name="OrganisationSpecialist" table="organisation_specialist">
<composite-id mapped="false" unsaved-value="undefined">
<key-many-to-one class="Organisation" column="ORGANISATION_ID" lazy="false" name="organisation" />
<key-many-to-one class="Specialist" column="SPECIALIST_ID" lazy="false" name="specialist" />
</composite-id>
</class>
The following code works
Criteria criteria = session.createCriteria(OrganisationSpecialist.class);
criteria.add(Restrictions.eq("organisation.organisationId", organisationId));
When I add an statement with a property present in my model Organisation like this:
Criteria criteria = session.createCriteria(OrganisationSpecialist.class);
criteria.add(Restrictions.eq("organisation.organisationId", organisationId));
criteria.add(Restrictions.eq("organisation.deleted", true));
I get the error message:
org.hibernate.QueryException: could not resolve property: organisation.deleted of: ch.xxx.yyy.model.OrganisationSpecialist
I also tried using alias for the property deleted like this:
Criteria criteria = session.createCriteria(OrganisationSpecialist.class);
criteria.add(Restrictions.eq("organisation.organisationId", organisationId));
criteria.createAlias("organisation", "o").add(Restrictions.eq("o.deleted", false));
criteria.add(Restrictions.eq("organisation.deleted", true));
When I'm using HQL Query, my query works.
Query query = session.createQuery("from OrganisationSpecialist where organisation.organisationId=:orgId and organisation.deleted=false");
query.setParameter("orgId", organisationId);
Can somebody explain me what I'm doing wrong? I thought that every query possible in HQL are also possible using Criteria.
Thanks for explanation

Strange behaviour with composite-id and version in hibernate 3.6

I encounter strange behaviour on Hibernate's merge() if I use an entity with a composite-id and a version number.
This is my hibernate mapping file:
<class name="ArticleTurnover" table="T_ARTICLETURNOVER">
<composite-id>
<key-property name="mainArticleId" type="java.lang.Integer" column="ARTICLETURNOVER_ID"/>
<key-property name="locationId" type="java.lang.Integer" column="ARTICLETURNOVER_LOCATIONID"/>
</composite-id>
<version name="version" column="ARTICLETURNOVER_VERSION" />
... some properties
</class>
And this is the code (it fails...):
ArticleTurnover at = new ArticleTurnover();
at.setMainArticleId(1);
at.setLocationId(1);
ArticleTurnover savedAt = em.merge(at);
assertNotNull(savedAt.getMainArticleId());
assertNotNull(savedAt.getLocationId());
After calling merge the fields mainArticleId and locationId are both null. The code above is just a test, but if I would commit a transaction, hibernate would insert null into the composite-id fields, and fail!
If I change em.merge(at) to em.persist(at) everything works. And if I manually set at.setVersion(0) (!!) it also works.
I ended up in adding a component type ArticleTurnoverId for my composite-id like mentioned here: http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/mapping.html#d0e4819.
Can anybody tell me what I am doing wrong, or point out why this happens?

Hibernate retrieves many-to-one without asking

we have a big problem in our development team.
We are using Hibernate and we have some entities which are related in two transitive one-to-many relations. The main object is a Group which has a list of Property instances, and each Property containing a list of Values.
(The mappings are down ahead)
We have two main problems:
A) When making a HQL Query, Criteria Query or SQLQuery it doesn't matter the conditions applied in JOINs or WHERE clauses, Hibernate always retrieves for us all the underlying objects. For example, if I make a Criteria or SQL getting only the Group objects, Hibernate comes and (lazy or not) gets all the Property and Value instances too. We want to control this. We want to do left joins and get only the properties with no values inside (Hibernate removes these properties with no value)
B) When making the Query, for example, a SQL, it shows in the log the SQL code we want. Everything seems perfect. But after that it brings every instance in the list without applying conditions, getting them only by id, and we can assure this because with lazy="true" we see the "load many-to-one" queries in the log.
Is there something we can do in hibernate config, fetching mode/strategy, the mappings configuration or anywhere? I'm thinking on going on Result transformers now.
I would be grateful if someone coud give me a hint or tell me where to find a solution to this problem. We are confused about how to get this, but it must be a way.
Thanks in advance
Query:
Criteria lstCriterios = this.getSession().createCriteria(CardGroup.class, CARD_GROUP)
.add(Restrictions.eq(ID_CATEGORY, idCategory));
lstCriterios.createAlias("listProperty", "listProperty", CriteriaSpecification.LEFT_JOIN);
if (clusterId != null) {
lstCriterios.add(Restrictions.or(
Restrictions.isNull("listPropertyValue" + ".value"),
Restrictions.and(Restrictions.eq("listPropertyValue" + ".clusterId", clusterId),
Restrictions.eq("listPropertValue" + ".companyWarehouseId", idCompanyWarehouse))));
lstCriterios
.createAlias("listProperty" + "." + "listPropertyValue", "listPropertyValue",
CriteriaSpecification.LEFT_JOIN,
Restrictions.eq("listPropertyValue" + ".clusterId", clusterId));
} else {
lstCriterios.createAlias("listProperty" + ".listPropertyValue", "listPropertyValue",
CriteriaSpecification.LEFT_JOIN);
}
lstCriterios.add(Restrictions.eq(ID_CATEGORY, idCategory));
lstCriterios.add(Restrictions.eq("listProperty" + ".groupId", idGroup));
lstCriterios.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
/*
* Sorting
*/
lstCriterios.addOrder(Order.asc("order"));
lstCriterios.addOrder(Order.asc("listProperty" + ".order"));
lstCriterios.addOrder(Order.asc("listPropertyValue"+ ".clusterId")); // Agrupacion, podrĂ­a ser nulo
lstCriterios.addOrder(Order.asc("listPropertyValue"+ ".propertyId")); // Propiedad
lstCriterios.addOrder(Order.asc("listPropertyValue"+ ".id"));
return lstCriterios.list();
Group mapping:
<list name="listProperty"
table="FICHA_PROPIEDAD" schema="${db2.siglo.schema}"
inverse="false" cascade="all" >
<key column="ID_FICHA_GRUPO" not-null="false" />
<list-index column="ORDEN" base="1"/>
<one-to-many
class="com.company.aslo.appwebsiglo.model.card.property.property.CardProperty" />
</list>
Property mapping:
<bag name="listPropertyValue"
table="FICHA_PROPIEDAD_VALOR" schema="${db2.siglo.schema}"
inverse="false" cascade="all">
<key column="ID_FICHA_PROPIEDAD" not-null="false" />
<one-to-many
class="com.company.aslo.appwebsiglo.model.card.propertyvalue.propertyvalue.CardPropertyValue" />
</bag>
It seems like our model design was bad and we didn't realize that if the DB table FICHA_PROPIEDAD_VALOR has Composite Key we can't map only one of the attributes in the composite key, because it brings us unexpected results.
Because of this and the nested objects, we had also bad implementations of the hashCode() and equals() methods which Hibernate uses.
I had solved this previously with a ResultTransformer getting the rows from a SQLQuery, but we got the Hibernate solution after that refactoring and changing the design of our model.

Hibernate mapping with one-to-many polymorphic relationship

I have the following class diagram and I want to map it to a database (note that Person has a list with objects of class Vehicle).
Also my database looks like:
All tables in the database that represent a subclass of the Vehicle class have all the fields of the superclass Vehicle. Also, all the relations show a one-to-many relationship from Person to Vehicle, Car and Motorcycle.
My hibernate mapping files are the following:
Person.hbm.xml
<hibernate-mapping package="....">
<class name="Person" table="Persons">
<id name="key" column="Person_ID">
<generator class="native"/>
</id>
<list name="ownedVehicles" inverse="false" cascade="all">
<key column="Person_ID" not-null="true" />
<list-index column="idx"/>
<one-to-many class="Vehicle"/>
</list>
</class>
</hibernate-mapping>
Vehicle.hbm.xml
<hibernate-mapping package="...">
<class name="Vehicle" table="Vehicles" polymorphism="implicit">
<id name="id" type="int" column="Vehicle_ID">
<generator class="increment"/>
</id>
<property name="numOfSeats"/>
<union-subclass name="Car" table="Cars"></union-subclass>
<union-subclass name="Motorcycle" table="Motorcycles"></union-subclass>
</class>
</hibernate-mapping>
The problem (error I get) is the following:
Hibernate: insert into Persons (Person_ID) values (default)
2013-06-26 15:41:52 WARN JdbcCoordinatorImpl:424 - HHH000386: ResultSet had no statement associated with it, but was not yet registered
Hibernate: update Car set numOfSeats=? where Vehicle_ID=?
org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
I get this error when I run:
Car car = new Car();
car.setNumOfSeats(5);
Person person = new Person();
person.getOwnedVehicles().add(car);
ManagePerson managePerson = new ManagePerson();
Integer personID = managePerson.store(person);
The store() function of ManagePerson actually creates a session and a transaction and then uses the save() method provided by Hibernate to persist the objects into the database.
As far as I understand Hibernate usually will do insert into Persons, then insert into Cars and finally update Cars (the update is done to save the foreign keys on Cars table that will reference the Person that owns the cars). However, here this is not the case and the insert into Cars seems to be getting skipped. I understood how Hibernate works here by trying person.getOwnedVehicles().add(vehicle); instead of person.getOwnedVehicles().add(car); on the code given above.
As you might understand, I am trying to see if Hibernate actually understands in which "subclass" table a record should go, depending on the class of the object contained in the ownedVehicle list of the Person class. For example, if the ownedVehicles has an object of class Car and one of class Motorcycle, then each of these should go to Cars and Motorcycle tables respectively.
Note: I am using Hibernate 4.2.2 and HSQLDB 2.2.9.
I would appreciate any help with this.
Thanks.
I think it is just a matter of incorrect use of the implicit polymorphism of Hibernate.
Implicit polymorphism for your case can only work by changing your list to have
inverse="true". This can be done of course if your Vehicle class also 'knows' about the relationship with the Person class (e.g. by adding an 'Owner' property and the corresponding mapping).
(Have a look at this table and the case of "table per concrete-class (union-subclass)" and one-to-many associations.
If you enable logging and raise the log level to DEBUG you would see that currently Hibernate tries to update the Vehicles table with the Person_ID instead of the Car table like you meant it to. This is because of the inverse="true" and the limitations of the combination of the Table-per-concrete-class mapping strategy and implicit polymorphism (have a look at the documentation).
So, by having the Vehicle class know about its Owner and using inverse="true" you should be able to succeed in what you are trying to do. Either this or try one of the other inheritance mapping strategies (again have a look at the documentation).
If the managePerson.store(...) method doesn't have a recursive call to the objects in "getOwnedVehicles()" such that it can then call their "store" methods then you shouldn't expect that the created "car" object would be inserted into the table.
You are in fact calling "managePerson.store" not "manageCar.store", I'd have to see the code in the .store(...) method to be sure though but I would expect that it is not doing an iteration of the Vehicles and is not doing an insert for any discovered ones (why should it unless you built it explicitly to do that?).

Beginners Hibernate problem - simple mapping with non-simple exception!

Please help me with this hibernate problem, I'm new to hibernate and still trying to get my head around it. I can't seem to work this issue out. I imagine I'm missing something pretty simple.
I've followed the example here to achieve a many-to-one mapping, as my requirements are almost identical: http://www.coderanch.com/t/217519/ORM/java/Hibernate-Newbie-Many-Relation-Tutorial
Please note that when I try to persist the Picture object, the user variable is (at that point in time) empty, as is every other variable bar image.
Also note that I've set hibernate to generate the database schema by itself via config in the hibernate config file.
Here are my mapping files (declarations removed)
User.hbm.xml
<class name="msc.model.User" table="USER">
<id name="id" column="USER_ID">
<generator class="native"/>
</id>
<property name="username"/>
<property name="email"/>
<bag name="pictures"
table="PICTURE"
lazy="true"
cascade="save-update">
<key column="PICTURE_ID"/>
<one-to-many class="msc.model.Picture" />
</bag>
</class>
And Picture.hbm.xml
<class name="msc.model.Picture" table="PICTURE">
<id name="id" column="PICTURE_ID">
<generator class="native"/>
</id>
<property name="story"/>
<property name="tattooist"/>
<property name="pic"/>
<many-to-one name="user"
class="msc.model.User"
column="USER" />
<property name="image" type="blob">
<column name="IMAGE" not-null="true" />
</property>
</class>
The class files (getters and setters stripped)
Picture.java
package msc.model;
import java.io.File;
import java.sql.Blob;
public class Picture {
private Long id = null;
private User user = null;
private File pic = null;
private String story = null;
private String tattooist = null;
private Blob image = null;
}
User.java
package msc.model;
import java.util.ArrayList;
import java.util.List;
public class User {
private Long id = null;
private String username = null;
private String email = null;
private List<Picture> pictures = null;
}
The persistence code (note that bFile is byte stream created from a file):
Session hib_ses = HibernateUtil.getSessionFactory().getCurrentSession();
hib_ses.beginTransaction();
Picture picture = new Picture();
picture.setImage(Hibernate.createBlob(bFile));
Long id = (Long) hib_ses.save(picture);
hib_ses.getTransaction().commit();
Here is the exception:
Cannot add or update a child row: a foreign key constraint fails (`msc`.`picture`, CONSTRAINT `FK85BE8DE2885129D` FOREIGN KEY (`PICTURE_ID`) REFERENCES `user` (`USER_ID`))
Please help!
There is something very strange going on if that is the real error you get.
Cannot add or update a child row: a foreign key constraint fails (`msc`.`picture`, CONSTRAINT `FK85BE8DE2885129D` FOREIGN KEY (`PICTURE_ID`) REFERENCES `user` (`USER_ID`))
This says that PICTURE.PICTURE_ID is a reference to USER.USER_ID. But PICTURE_ID is the PK of picture, which Hibernate will generate upon insertion. Did you mean to create a constraint from PICTURE.USER to USER.USER_ID?
Oh, I see you wrote you generate the schema via Hibernate. I think the error is in your "bag" definition. The key column should not be PICTURE_ID, but USER.
It looks like you are trying to save the Picture before saving the User. Try saving the User first.
[edit]
From the mapping - it looks like there is a Parent/Child relationship between User and Picture.
There is a good example in the Hibernate Documentation for a Parent Child relationship.
If you want the User to be able to be null, then a uni-directional relationship would be better.
[edit]
Another good reference about mapping collections with Hibernate.

Categories