Reputation: 820
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.
Upvotes: 2
Views: 3935
Reputation: 1219
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
Upvotes: 0
Reputation: 70584
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();
Upvotes: 0
Reputation: 41145
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.
Upvotes: 4
Reputation: 41145
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))
Upvotes: 0