Just taking another look I can see a couple of issues. 1. Are categoryId and parentCategoryId long's? If so, findById() should take a long (not a string). If they are strings, the query should use setString() instead of setLong(). Something has to change ;)
2. getChildren() should use Restrictions.eq("parentCategoryId", note.getCategory().getId()) 3. CategoryTreeModelAdapter should reference the interface of the DAO, not the concrete type. 4. In your page, you probably don't need a variable to store the TreeModel (the getter should be sufficient). 5. As I said earlier, the DAO might be better off being declared in the Tapestry IOC registry. This would mean it's a singleton and can be @Inject'ed. I'd do this after getting everything else working. Once you have a working example, please post it back to the list. I think this sounds like a prime candidate for adding to JumpStart ( http://jumpstart.doublenegative.com.au) On Thursday, 16 February 2012, Lance Java <lance.j...@googlemail.com> wrote: > Hi George > > As I said, my hibernate is a bit rusty. What I have given you there is a JDBC query where each question mark represents a parameter which is later set by Query.setLong(int paramIndex, Long value). You might need to research or chat on hibernate forums to turn it into a hibernate friendly query. Actually, I just looked at the hibernate javadoc and it says that it supports JDBC style '?' parameters so it might just work but I'm not 100%. You could always look at using a hibernate criteria query and using a projection to get the count() of children. Again, ask on the hibernate forums for this. > > <rant> > I actually really dislike hibernate because I think it makes smart people write stupid code. I have turned on SQL logging on hibernate applications only to be disgusted by seeing many unnecessary extra queries, joins and n+1 selects issues. If the developers were coding their queries by hand, this would have never happened. I happen to prefer iBatis / myBatis for it's hands on approach. Since the db is often the slowest component in your system, I hate to be so far abstracted from it. > </rant> > > Apart from that your code looks ok although I would probably make the DAO a service and add it to Tapestry's IOC registry and then @Inject the DAO. What you have at the moment should work though so it's probably best to get the query working first. > > Good luck, > Lance. > > On Thursday, 16 February 2012, George Christman <gchrist...@cardaddy.com> wrote: >> Hi Lance, I'd like to share my progress with you. I think it will work once >> we get the hibernate sql query corrected. If you wouldn't mind taking a >> brief look at my classes to be sure I implemented everything correctly, it >> would be greatly appreciated. I could always get a little assistance from >> the hibernate guys too if we can't figure out that query. I seen a ? in the >> question stringbuilder method. Is that a place holder or is there some kind >> of logic behind it. Once again thanks, >> >> Cheers, >> George >> >> @Entity >> public class Category extends BaseEntity { >> >> private String label; >> >> @OneToMany(mappedBy = "parentCategoryId") >> private List<Category> children; >> >> @ManyToOne >> @JoinColumn(name = "parent_id") >> private Category parentCategoryId; >> >> //Getters Setters >> >> >> >> >> >> public class CategoryNode { >> >> private Category category; >> private boolean isLeaf; >> private boolean hasChildren; >> >> //Getters Setters >> >> >> >> >> >> public class HibernateCategoryDao implements CategoryDao { >> >> private final Session session; >> >> public HibernateCategoryDao(Session session) { >> this.session = session; >> } >> >> // this will be called by ValueEncoder.toValue(id) >> public CategoryNode findById(String id) { >> return findByCriterion(Restrictions.eq("categoryId", >> id)).iterator().next(); >> } >> >> // this will be called by TreeModelAdapter.getChildren(CategoryNode >> node) >> public List<CategoryNode> getChildren(CategoryNode node) { >> return findByCriterion(Restrictions.eq("parentCategoryId", >> node.getCategory())); >> } >> >> // this will be called by your page >> public List<CategoryNode> findRoots() { >> return findByCriterion(Restrictions.isNull("parentCategoryId")); >> } >> >> @SuppressWarnings("unchecked") >> protected List<CategoryNode> findByCriterion(Criterion criterion) { >> List<Category> cats = >> session.createCriteria(Category.class).add(criterion).list(); >> Map<Integer, CategoryNode> childNodes = new LinkedHashMap<Integer, >> CategoryNode>(); >> for (Category cat : cats) { >> CategoryNode childNode = new CategoryNode(); >> childNode.setCategory(cat); >> childNodes.put(cat.getId(), childNode); >> } >> StringBuilder questions = new StringBuilder(); >> for (int i = 0; i < childNodes.size(); ++i) { >> if (i != 0) { >> questions.append(", "); >> } >> questions.append("?"); >> } >> >> >> Query query = session.createSQLQuery( >> "select c1.id, count(c2.*) " >> + "from Category c1 " >> + "left join Category c2 on c2.parentCategoryId = c1.id " >> + "where c1.id in (" + questions + ") " >> + "group by c1.id"); >> >> int i = 0; >> >> for (Iterator<CategoryNode> it = >> childNodes.values().iterator(); i < childNodes.size(); ++i) { >> query.setLong(i + 1, >> it.next().getCategory().getId()); >> } >> >> for (Iterator<Object[]> it = query.iterate(); it.hasNext();) { >> Object[] result = it.next(); >> Integer childId = (Integer) result[0]; >> Integer grandChildCount = (Integer) result[1]; >> CategoryNode childNode = childNodes.get(childId); >> childNode.setHasChildren(grandChildCount != 0); >> childNode.setIsLeaf(grandChildCount == 0); >> } >> >> return new ArrayList<CategoryNode>(childNodes.values()); >> } >> >> } >> >> >> >> public interface CategoryDao { >> >> public CategoryNode findById(String id); >> >> public List<Categor