2

I have a list of items. Each item has set of categories. I want to grab all the items of a specific category. This part is simple. The part I am having problems with is getting my query to return the item with all of its categories, not just the one I am filtering on.

session.createCriteria(Item.class)
        .createAlias("categories","category")
        .add(Restrictions.eq("category.name",categoryFilter))

The above code returns the item but only with the category I am filtering on. Is there anyway to say filter the object on this restriction, but return the full object and not the filtered one? I have also tried writing this in HQL with the same results.

UmYeah
  • 810
  • 2
  • 14
  • 21

4 Answers4

4

It appears there really is some nasty interaction between FetchMode and createAlias, which looks like a bug to me.

There's some discussion of this at https://forums.hibernate.org/viewtopic.php?t=944439 with one of the developers saying emphatically that it's correct behavior and won't be fixed.

The discussion also contains potential workarounds though.

Try using a nested criteria instead of an alias:

session.createCriteria(Item.class)
   .createCriteria("categories")
       .add(Restrictions.eq("name",categoryFilter))

With the collection mapped as eager, this seems to work for me. Not sure of interaction with using FetchMode on the outer criteria.

Don Roby
  • 40,677
  • 6
  • 91
  • 113
0

Another solution is to use an Exists Subquery so that FetchMode.JOIN will also work. (This uses DetachedCriteria but Criteria should be similar)

DetachedCriteria criteria = session.createCriteria(Item.class, "i");
criteria.setFetchMode("categories", FetchMode.JOIN);

DetachedCriteria catCriteria = DetachedCriteria.forClass(Category.class, "category");
catCriteria.add(Restrictions.eq("name", categoryFilter));
catCriteria.add(Restrictions.eqProperty("category.id", "i.categoryId"));
criteria.add(Subqueries.exists(catCriteria.setProjection(Projections.property("category.id"))));

Hope this helps someone else too since the docs are so hard to figure out. I also added a github gist with additional comments

Jeff Sheets
  • 1,181
  • 12
  • 18
0

This likely has not much to do with the use of the alias and restriction, but is just a result of default lazy fetching.

In your mapping of Item, you probably have categories set to fetch lazily, which is the default, and generally a good idea.

You can change this mapping to eager, but that's probably a bad idea.

To leave the default fetch lazy but make the specific criteria retrieve eagerly, you can set the fetch mode there, with something resembling

session.createCriteria(Item.class)
    .setFetchMode("categories", FetchMode.EAGER)
    .createAlias("categories","category")
    .add(Restrictions.eq("category.name",categoryFilter))
Don Roby
  • 40,677
  • 6
  • 91
  • 113
  • 1
    I have double checked the mapping which is eager and I have set the fetchmode as you have shown. Neither has done the trick. – UmYeah Jan 30 '10 at 05:04
  • I've now experimented with a similar situation and indeed this doesn't work. I don't yet have the needed version of hibernate for the fix myself, but there was revision allowing specification of FetchType as a third argument to createAlias, which may do it. See http://opensource.atlassian.com/projects/hibernate/browse/HHH-1696 – Don Roby Jan 30 '10 at 12:53
  • On my own comment - I do have that overload in Criteria, but it's not FetchType that is the third argument, it's CriteriaSpecification. I haven't seen it correct this issue though. The jira referenced was for adding this overload to DetachedCriteria, which isn't in play here. – Don Roby Jan 30 '10 at 13:26
  • I tried setting the third argument as Left_Join which has the usual results. I also tried using Full_Join which created a broken SQL query. – UmYeah Jan 30 '10 at 16:36
0

If it is the bug I reported a while ago: My usual work-around is only fetch the id's of the matching items, and then select the items with their categories in a follow-up query:

List<Serializable> ids = session.createCriteria(Item.class)
    .createAlias("categories","category")
    .add(Restrictions.eq("category.name",categoryFilter))
    .setProjection(Projections.id())
    .list();

List<Items> items = session.createCriteria(Item.class)
    .add(Restrictions.in("id", ids)
    .createAlias("categories","category")
    .list();
meriton
  • 68,356
  • 14
  • 108
  • 175