Jared
Jared

Reputation: 2133

How to do a subquery on the same table in Hibernate?

I have an Oracle table called item_association and an accompanying Hibernate Entity. Here is an example of rows in that table:

id   group_id  item_id  type   value
====================================
1    1         1234     'lang' 'en' 
2    1         2345     'lang' 'fr'

I want to query that table to retrieve all ItemAssociations that share a group_id with a specific item_id, and exclude that item_id itself. The SQL would be:

select group_id, item_id, type, value
from ITEM_ASSOCIATION
where group_id in (select group_id from ITEM_ASSOCIATION where item_id = :itemId)
and item_id <> :itemId

I am trying to use the following Hibernate criteria to accomplish that, but I get: org.hibernate.MappingException: Unknown entity: null

DetachedCriteria subquery = DetachedCriteria.forClass(ItemAssociation.class)
                    .add(Restrictions.eq("itemId", itemId))
                    .setProjection(Projections.property("groupId"));

Criteria query = session.createCriteria(ItemAssociation.class)
                    .add(Property.forName("itemId").in(subquery))
                    .add(Restrictions.not(Restrictions.eq("itemId", itemId)));

ItemAssociation.java:

@Entity
@Table(name = "ITEM_ASSOCIATION")
public class ItemAssociation {
    @Id
    @GeneratedValue
    private Long id;

    @Column(name = "group_id")
    private Long groupId;

    @OneToOne
    @JoinColumn(name = "item_id", insertable = false, updatable = false)
    private Item item;

    @Column
    private String type;

    @Column
    private String value;

    public Long getGroupId() {
        return groupId;
    }

    public void setGroupId(Long groupId) {
        this.groupId = groupId;
    }

    public Item getItem() {
        return item;
    }

    public void setItemId(Item item) {
        this.item = item;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
}

Upvotes: 3

Views: 2102

Answers (2)

Jared
Jared

Reputation: 2133

This one was just an oversight on my part. Since the ItemAssociation entity contains an Item reference instead of the itemId field, I needed to change itemId to item.id in my queries. Also, the first itemId in query is supposed to be groupId:

DetachedCriteria subquery = DetachedCriteria.forClass(ItemAssociation.class)
                    .add(Restrictions.eq("item.id", itemId))
                    .setProjection(Projections.property("groupId"));

Criteria query = session.createCriteria(ItemAssociation.class)
                    .add(Property.forName("groupId").in(subquery))
                    .add(Restrictions.not(Restrictions.eq("item.id", itemId)));

Upvotes: 1

Lucas Oliveira
Lucas Oliveira

Reputation: 3477

Use org.hibernate.criterion.Subqueries#propertyIn(String propertyName, DetachedCriteria dc)

(...)
Criteria query = session.createCriteria(ItemAssociation.class)
                .add(Subqueries.propertyIn("itemId",subquery))
                .add(Restrictions.not(Restrictions.eq("itemId", itemId)));
(...)

Upvotes: 0

Related Questions