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.
Related
I found many times on stackoverflow this issue, but nothing from them gives me clear answer. For simplicity, there are only two tables film and language bound many to one relation. Everything done according Netbeans Hibernate DVD Store tutorial. Now, how to display in first page (index.xhtml) language. It looks like very straightforward. Simply add:
<h:column>
<f:facet name="header">
<h:outputText value="Language"/>
</f:facet>
<h:outputText value="#{item.languageByLanguageId.langName}"/>
</h:column>
(Comumn in table language name was renamed on langName)
But it issues still the same LazyInitializationException. I tried to obtain languageId and in this case I was successful. It means #{item.languageByLanguageId.langName} gives exception but #{item.languageByLanguageId.languageId} not. It is strange. So what happen, when I use explicit fetch according languageId if I can obtain its.
So I added in FilmController.java method for obtaining language:
public String getLanguageById(Integer langId) {
String language = helper.getLangById(langId);
return language;
}
And in FilmHelper.java (final version):
public Film getFilmById(int filmId) {
Film film = null;
try {
session = HibernateUtil.getSessionFactory().getCurrentSession();
org.hibernate.Transaction tx = session.beginTransaction();
Query q = session.createQuery("select count(film.filmId) from Film as film where film.filmId = :filmId");
q.setParameter("filmId", filmId);
Number count = (Number) q.uniqueResult();
if (count.intValue() > 0)
film = (Film) session.load(Film.class, filmId);
tx.commit();
} catch (Exception e) {
e.printStackTrace();
}
return film;
}
And yes, it works, I can obtain language name to modify index.xhtml:
<h:outputText value="{filmController.getLanguageById(item.languageByLanguageId.languageId)}"/>
Than I tried to modify FilmActor.hbm.xml to add lazy="false" and use origin simple solution in index.xhtml ("#{item.languageByLanguageId.langName}"):
<many-to-one name="languageByOriginalLanguageId" class="dvdrental.Language" lazy="false" fetch="select">
<column name="original_language_id" />
</many-to-one>
Again it works properly. Even if I set lazy="proxy" or lazy="no proxy". But still I don't understand, how to use this default attribute lazy="true". If I try to keep whole document in one session (don't do commit, which causes end of session), there is another Exception issue. It looks like, that lazy="true" doesn't meet in any time proper result.
With setting lazy=true attribute you are allowing hibernate to delay association retrieving. So when you disable lazy=false then hibernate will immediate do its fetching method, just after parent instance is retrieved. Yours problem will be solved if you set fetch="join".
Join fetching: Hibernate retrieves the associated instance or
collection in the same SELECT, using an OUTER JOIN.
Your example;
<many-to-one name="languageByOriginalLanguageId" class="dvdrental.Language" fetch="join">
<column name="original_language_id" />
</many-to-one>
You can look at fetch and lazy as how and when, respectively. In your example lazy=false solved your problem but still two queries where done because your fetch method was select.
Hibernate Fetching Strategies
UPDATE
Once when object is lazy initialized, you have only properties of your entity and lazy initialized association (only id you have). Then that object is passed for further(transaction is committed already) use and you want to use one of lazy initialized association(in your case Language) and got exception. This is happening because you are accessing lazy object and your transaction is already commited, so hibernate wants to execute your second query without success (fetch="select"). This can be fixed by moving the code that reads association to just before the transaction is committed.
When your object is detached and your current session is closed then you must do
Hibernate.initialize(entity)
to assign your detached entity to another session.
Thank you for explanation. I tested your advice. It works and I suppose, that join should be quicker than two distinct selects (it depends on indexes, optimizer, etc.), but still when I try combination lazy="true" and fetch="join" it again fails:
<many-to-one name="languageByOriginalLanguageId" class="dvdrental.Language" lazy="true" fetch="join">
<column name="original_language_id" />
</many-to-one>
Even if exception is different, still no succes:
java.lang.ExceptionInInitializerError
at controller.HibernateUtil.<clinit>(HibernateUtil.java:30)
However, there are clearly explained three ways, how to avoid problems with default or explicit lazy="true".
Hibernate 4.1 with XML mappings, Struts 1.3, multi-app environment sharing the same database. Let's say we have three tables:
Client Car_Client House_Client
------ ---------- ------------
id client_id client_id
name date_purchased date_purchased
The 3 mapping files:
<hibernate-mapping>
<joined-subclass name="CarClient" extends="Client" table="Car_Client">
<key column="client_id" />
<property name="datePurchased">
<column name="date_purchased" />
</property>
</joined-subclass>
</hibernate-mapping>
<hibernate-mapping>
<joined-subclass name="HouseClient" table="House_Client">
<key column="client_id" />
<property name="datePurchased">
<column name="date_purchased" />
</property>
</joined-subclass>
</hibernate-mapping>
Client is the parent object and the two applications(Car and House) share the parent table but each have their own subclass of the parent table to store extra information about the client. Each Hibernate mapping and Java class is extending the parent object.
So in normal use, when the Car app deletes a CarClient, the parent object is also deleted as usually a client exists in only one app. Sometimes though, a client may exist in both apps. Deleting that client from one app will remove the record from the child table and throw a ConstraintViolationException on the parent table.
Our solution is deleting the child record with an SQL query as HQL would try to delete the parent. We then have to refresh the cache so Hibernate knows the child record no longer exists.
Is there a way in Java to tell Hibernate to only delete the child record? Basically override the built-in behavior that deletes the parent object? Without having to write a custom query? May not be possible but I am curious if I'm missing something.
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.
As per Hibernate docs for one-to-many xml mapping tag there is an attribute called as not-found
http://docs.jboss.org/hibernate/orm/3.3/reference/en-US/html/collections.html#collections-onetomany
The Doc says:
not-found (optional - defaults to exception): specifies how cached
identifiers that reference missing rows will be handled. ignore will
treat a missing row as a null association.
What is the use of this attribute? I tried to create a mapping between Product and Parts with Product having a set of Parts with below mapping details:
<set name="parts" cascade="all">
<key column="productSerialNumber" not-null="true" />
<one-to-many class="Part" not-found="ignore"/>
</set>
Then I wrote my Java code as:
public static void main(String[] args) {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
Product prod = (Product) session.get(Product.class, 1);
session.getTransaction().commit();
System.out.println(prod);
HibernateUtil.getSessionFactory().close();
}
I was expecting null for my set which has Parts as I configured in my mapping file as not-found="ignore". But I got the regular exception - org.hibernate.LazyInitializationException
Please help me in understanding what is the use of this attribute? What are cached identifiers here?
The not-found has nothing to do with lazy loading. It's used to handle incoherences in your database.
Suppose you know nothing about good database practices, and have an order_line table containing an order_id column, supposed to reference the order it belongs to. And suppose that since you know nothing about good practices, you don't have a foreign key constraint on this column.
Deleting an order will thus be possible, even if the order has order lines referencing it. When loading such an OrderLine with Hibernate, Hibernate will load the Order and fail with an exception because it's supposed to exist, but doesn't.
Using not-found=ignore makes Hibernate ignore the order_id in the OrderLine, and will thus initialize the order field to null.
In a well-designed database, this attribute should never be used.
I have a spring-hibernate application which is failing to map an object properly: basically I have 2 domain objects, a Post and a User. The semantics are that every Post has 1 corresponding User.
The Post domain object looks roughly as follows:
class Post {
private int pId;
private String attribute;
...
private User user;
//getters and setters here
}
As you can see, Post contains a reference to User. When I load a Post object, I want to corresponding User object to be loaded (lazily - only when its needed).
My mapping looks as follows:
<class name="com...Post" table="post">
<id name="pId" column="PostId" />
<property name="attribute" column="Attribute" type="java.lang.String" />
<one-to-one name="User" fetch="join"
class="com...User"></one-to-one>
</class>
And of course I have a basic mapping for User set up.
As far as my table schema is concerned, I have a table called post with a foreign UserId which links to the user table.
I thought this setup should work, BUT when I load a page that forces the lazy loading of the User object, I notice the following Hiberate query being generated:
Select ... from post this_ left outer join user user2_ on this.PostId=user2_.UserId ...
Obviously this is wrong: it should be joining UserId from post with UserId from user, but instead its incorrectly joining PostId from post (its primary key) with UserId from user.
Any ideas? Thanks!
Update:
Thanks to a couple of the posts below I now realize that I should have been using a many-to-one mapping instead of a one-to-one. I changed the mapping under post to the following:
<many-to-one name="User" class="com...User" column="uId"/>
But now I get a run-time error telling me that there is no attribute called uId. This makes sense since I do not have a uId column in my post domain object (I simply have a reference to a user object). Now I am really confused as to how I can get Hibernate to realize that it needs to map the foreign key from the post table to the user table. Should explicitly add a uId attribute to my post domain object to be a placeholder for the foreign key?
I hope I am making sense...
Since a user has many posts, your association is in fact a "many-to-one", not a "one-to-one". It should work if you map it accordingly.
Edit: Yes, you can map the property Post.user on the Post with a "many-to-one", or the set User.posts in User with a "one-to-many", or both. Have you specified the name of your foreign key column?
Edit2: In Hibernate speak, a "column" in the database is mapped to a "property" in your Java-Class. That is, the column attribute contains the name of your foreign key column in the database, not the name of any property in your Java class. If I read your question right, you should use "UserId", not "uId".
Oh, and a fetch="join" can not be lazy, as it mandates that the user is fetched in the same query as the post.
That is the behaviour of a one-to-one mapping. They usually share a primary key. Hibernate is assuming that the primary key of post is teh same as the primary key of user. This page summarizes this behaviour.
I suspect that one user can actually have more than one posts though. That makes your mapping a one-to-many.