简体   繁体   中英

Hibernate criteria many to many

I have two entities with many to many relationship:

@Entity
@Table(name = "items")
public class Item implements Comparable {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "item_id")
private Integer itemId;

@ManyToMany(cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)
@JoinTable(name = "items_criteria",
        joinColumns = @JoinColumn(name = "item_id"),
        inverseJoinColumns = @JoinColumn(name = "filter_criterion_id"))
private List<FilterCriterion> filterCriteria;

}

and

@Entity
@Table(name = "filter_criteria")
public class FilterCriterion {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "filter_criterion_id")
private Integer filterCriterionId;

@ManyToMany(cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)
@JoinTable(name = "items_criteria",
        joinColumns = @JoinColumn(name = "filter_criterion_id"),
        inverseJoinColumns = @JoinColumn(name = "item_id"))
private List<Item> items;
}

I need to write function in ItemDao class that returns List of Items which have all elements of the collection given as an argument. In the example below I use Restrictions.in so the result contains even those Items which contain for example only one FilterCriterion from List given as argument. I need to have in the result only those Items, which contain all of the elements in argument List.

public List<Item> getItems(List<FilterCriterion> currentFilterCriteria) {

    Criteria criteria = ht.getSessionFactory().getCurrentSession().createCriteria(Item.class);
    List<Integer>currentFilterCriteriaId = new ArrayList<Integer>();
    for(FilterCriterion criterion : currentFilterCriteria){
        currentFilterCriteriaId.add(criterion.getFilterCriterionId());
    }
    if(!currentFilterCriteriaId.isEmpty()){
        criteria.createAlias("filterCriteria", "f");
        criteria.add(Restrictions.in("f.filterCriterionId", currentFilterCriteriaId));
    }
    return criteria.list();
}

First of all, you'll have to fix your mapping. You don't have a bidirectional ManyToMany association here, but two, unrelated, unidirectional ManyToMany associations. One side must be the inverse side by using the mappedBy attribute:

@ManyToMany(mappedBy = "filterCriteria")
private List<Item> items;

Now to your question, one way of doing this is to use such a query. I'll let you translate it to Criteria if you really want to. I'd use HQL instead, since it's so much easier and maintainable:

select i from Item i
where :criteriaIdSetSize = (select count(c.id) from Item i2
                             inner join i2.filterCriteria c
                             where c.id in :criteriaIdSet
                             and i2 = i)

You should use a Set to hold your criteria IDs rather than a list though, to make sure it doesn't contain duplicates (which would make the result incorrect).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM