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
Related
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.
For example, I have the mapping file like this
<class name="my.test.model.Product" table="PRODUCT">
...
<set name="retailers" table="product_shop" lazy="false">
<key column="PRODUCT_ID" />
<many-to-many column="SHOP_ID" class="my.test.model.Shop" />
</set>
...
</class>
Now I want to query the Products of a particular Shop A. Something like this come to mind:
String searchHql = "select p from Product p inner join p.retailers retailing where p.retailers.shop_id = :shopId";
#SuppressWarnings("unchecked")
List<Product> productList = sessionFactory.getCurrentSession().createQuery(searchHql ).setInteger("shopId", shopId).list();
But it won't work. The error returned is:
could not resolve property: shop_id of: my.test.model.Shop. I have searched a lot, but still not find the right way to access the "many-to-many" subset in hql. Is this possible? Or I need to map the Product_Shop table to a model class?
UPDATE: as it seems there's no other way, I end up mapping Product_Shop into a class.
You're supposed to use the alias you assigned to the joined entity in the wgere clause:
select p from Product p inner join p.retailers retailing
where retailing.shop_id = :shopId
Side note: you should respect the Java naming conventions: shopId rather than shop_id.
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);
I have the following two table (which are tied in with Spring security - but the issue I believe is with Hibernate):
Table user
Table authority
The user table is tied (through Hibernate) to a domain object in my application: class User, which has the following attributes (and corresponding getters and setters), which correspond to columns in the user table (except for the Collection which is explained later):
long uId
String username
String password
...
Collection<GrantedAuthority> authorities
The authority table has 2 columns: UserId (foreign key into user table), and Authority (e.g. "ROLE_USER"). This table is NOT represented as a domain object, but is simply a collection in the User class.
To create the mapping, in my .hbm file I use the following:
<class name="com.business.project.domain.User" table="user">
<id name="uId" column="UserId"></id>
<property name="username" column="Name" type="java.lang.String" />
<property name="password" column="Password" type="java.lang.String" />
...
<set name="authorities" table="authority">
<key column="UserId" />
<element column="Authority" type="java.lang.String" />
</set>
</class>
In my hibernate DAO implementation, I create a query object, execute the query, and cast the result to a User object:
...
Query query = session.createQuery("from User where name = :username");
...
User user = (User) query.uniqueResult();
At this point, I would expect this object to be populated with the data that it pulled from the DB (I made sure that the tables are populated properly with test data and the mapping names are correct in the mapping file).
However, calling the getter methods for various attributes on the user object all return NULL for some reason. Can somebody see something immediately wrong with my setup? Perhaps I mapped the collection (to foreign key relationship) wrong? THANKS!
Update: here is the sql query that hibernate generated (taken from its DEBUG output):
Hibernate: select user0_.UserId as UserId1_, user0_.Name as Name1_,
user0_.Password as Password1_ from user user0_ where user0_.Name=?
For some reason, it doesn't show anything related to the authority table...does this mean that my mapping is incorrect?
Edit: Per bozho's suggestion, I took a look at the messages on the consol on startup (tomcat), but didn't see anything out of the ordinary:
Feb 16, 2010 10:35:12 AM org.hibernate.cfg.HbmBinder bindRootPersistentClassCommonValues
INFO: Mapping class: com.me.project.domain.User -> user
Feb 16, 2010 10:35:12 AM org.hibernate.cfg.HbmBinder bindCollection
INFO: Mapping collection: com.me.project.domain.User.authorities -> authority
Query query = session.craeteQuery("FROM User WHERE username = :username");
query.setString("username", "SomeUserName");
That should pretty much do it.
Try with "from User where username = :username"
HQL uses class properties, not db column names
Are you clearing the database everytime you run the test/java code? In hibernate there is a setting and when it is turned on, it can clear the database everytime a test/java code is run.
Can you do a findAll() and print the size? I very much suspect it is the wrong db, or no data in the db or clearing of data.
NOTE: Check for "hibernate.hbm2ddl.auto" property in your config file. If it is set to "create-drop" hibernate will auto create the schema on startup and delete the schema when VM shuts down. Just point it to "update" or something
http://docs.atlassian.com/hibernate2/2.1.8/reference/session-configuration.html
"Password" usually is a keyword in databases. It seems like you're hitting a name collision problem. Try the following. Put tick mark around the column name for escaping.
<property name="username" column="`Name`" type="java.lang.String" />
<property name="password" column="`Password`" type="java.lang.String" />
Assume you're using org.springframework.security.GrantedAuthority, then your mapping for authorities is incorrect. Based on the way you're mapping, when you access the collection, you most likely will get a ClassCastException. You probably want to use something like UerType to avoid the problem.
I have 2 tables:
orders: id
items: id, orderId, total, flag
I would like to make following query using Hibernate Criteria (DetachedCriteria):
SELECT
o.id,
SUM(i1.total),
SUM(i2.total)
FROM
orders o
LEFT JOIN
(
SELECT
i.orderId as orderId,
SUM(i.total) as total
FROM
items i
WHERE
i.flag = 0
GROUP BY
orderId
) AS i1
ON i1.orderId = o.id
LEFT JOIN
(
SELECT
i.orderId as orderId,
SUM(i.total) as total
FROM
items i
WHERE
i.flag = 1
GROUP BY
orderId
) AS i2
ON i2.orderId = o.id
GROUP BY
o.id
I know how to use DetachedCriteria to create subquery in WHERE clause, but as you can see, I need to do a subquery in FROM clause. If it is not possible, maybe there is a way to write it in SELECT clause (inside SUM()), because this query could be rewritten to such form.
I really need to use Criteria API even if I have to pass native SQL to the query.
I didn't show you classes or mapping, but as you can see, this is a very simple example.
I found solution for my problem. I had to make a POJO and mapping:
<class name="OrderTotal"
entity-name="OrderTotalForFlag0">
<subselect>
SELECT
i.orderId AS id,
SUM(i.total) AS total
FROM
items i
WHERE
i.flag = 0
GROUP BY
id
</subselect>
<id name="id" type="int" />
<property name="total" type="int" />
</class>
And of course for flag 1 it will be similar. This could be also done by declaring views in database and creating a mappings to that views. In this example I was using the same POJO class, but different entity-name.
Then I made a property in class Order and mapping:
<one-to-one name="orderTotalForFlag0" entity-name="OrderTotalForFlag0" />
<one-to-one name="orderTotalForFlag1" entity-name="OrderTotalForFlag1" />
Of course laziness could be set.
I'm pretty sure now, that this could be also done in different way - by making subquery in SELECT clause - using the formula attribute/element in mapping for properties, but this would work slower than subquery in FROM clause.
And of course all of that was in documentation to Hibernate ;)