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, bu开发者_JAVA百科t return the full object and not the filtered one? I have also tried writing this in HQL with the same results.
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.
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))
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();
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
精彩评论