Saturday, April 26, 2008

Hibernate & Java /Hibernate Annotations

Just a quick post on Hibernate ‘@Where’ annotation usage and a note on some odd behavior I’ve seen using Hibernate in Java (my environment NetBeans IDE 6.0 (Build 200711261600) Java: 1.5.0_13; Java HotSpot(TM) Client VM 1.5.0_13-119, System: Mac OS X version 10.5.2 running on i386; jboss: 4.2.2.GA; seam: 2.0.0.GA)

First, annotations:
I had a hard time finding a “pasteable” explanation of the use of @Where
Now that I’ve found how to do it, I thought I’d share.

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = “itemId”)

@Where(clause = “item_table = ‘competition’”)
public Set getItemTagRatings() {
return this.itemTagRatings;
}

public void setItemTagRatings(Set<> itemTagRatings) {
this.itemTagRatings = itemTagRatings;
}
The effect of this is to set up an additional condition upon TagRatings, so that only those TagRatings that have the item_table value = ‘competition’ are retrieved (item_table is the name of the column in the db).


The second item is odd. I cannot determine the underlying cause, so I’m just sharing the symptom and a workaround

The loop below would only execute once (and occasionally I would get a javax.faces.FacesException with the message: “#{competitionHome.persist}: java.util.ConcurrentModificationException”)

The concurrent modification exception was not a particular surprise, but the silent (no visible exception) execution of the loop a single time befuddles me. If supressWarnings wasn’t a compile time operation that’s where I’d place the blame but.... (BTW I have no doubt that I'm doing something deeply wrong in the not working loop below, my goal is to highlight the relatively opaque effect of the error)

Note: I designate the loop as ‘working’ since the query string shown will not work as written, it required some changes to work since the #{newName} did not evaluate to the appropriate value.

The loop


for((String newName : newTagNames){
@SuppressWarnings(“unchecked”)
List tags = (List) em.createQuery(“select t from Tag t where lower(t.tagName) = #{newName}“).setMaxResults(pageSize).setFirstResult(page * pageSize).getResultList();

if ((tags == null) || (tags.size() == 0)) {
newTag = new Tag(newName, user);
em.persist(newTag);
tagAssist.useTag(newTag);
}
else{
tagAssist.useTag(tags.get(0));
}
}



Breaking the loop up into multiple loops worked. The ‘working’ loop(s)


for ( String newName : newTagNames) {
ArrayList tags = null;
try {
Query q = em.createQuery(“select t from Tag t where lower(t.tagName) = #{newName} “);
q.setMaxResults(pageSize).setFirstResult(page * pageSize);
tags = (ArrayList) q.getResultList();
} catch ( IllegalStateException e) {
log.error(“error getting tags: “ + e);
e.printStackTrace();
} catch ( IllegalArgumentException e) {
log.error(“error getting tags: “ + e);
e.printStackTrace();
}
if ((tags == null) || (tags.size() == 0)) {
Tag newTag = new Tag(newName, currentUser);
newTags.add(newTag);
}
}
for ( Tag newTag : newTags) {
em.persist(newTag);
}
for ( Tag newTag : newTags) {
tagAssist.useTag(newTag);
}




2 comments:

www.examscam.com said...

that have the item_table value = ‘competition’

Is there an easy way to make the value of competition dynamic, like a property of the POJO, so that it can change with the given instance?

Thanks,

-Cameron McKenzie

rdf said...

That would be the default behavior for the "userText" object.

The goal of this code is to pick out only those text elements which are attached to this particular competition -- the way I have the system configured the (system generated) ids are only unique at the table level, not at the system level. That is, both the item_table and the item_id are necessary to identify the item which the text refers to.