简体   繁体   中英

How to filter entities with composite PK by a list of said PK using HQL?

Consider:

@Entity
public class Foo {
    @EmbeddedId
    private FooPK pk;

    public FooPK getPk() { return pk; }
    public void setPk(FooPK pk) { this.pk = pk; }
}

and

@Embeddable
public class FooPK {
    @Column(name="ID_A")
    private Long idA;

    @Column(name="ID_B")
    private Long idB;

    public Long getIdA() { return idA; }
    public void setIdA(Long idA) { this.idA = idA; }

    public Long getIdB() { return idB; }
    public void setIdB(Long idB) { this.idB = idB; }
}

I have a List<FooPK> that I'm trying to use as a filter in HQL:

-- Just an example of what I'm trying to do.
SELECT foo FROM Foo foo
WHERE foo.pk IN (:pkList)

This doesn't work, because pk is not a single value. I'm simply trying to list all of the entities that I have the pks from.

I can break the list and do something like this:

-- Ugly
SELECT foo FROM Foo foo
WHERE (
       (foo.pk.idA = :idA1 AND foo.pk.idB = :idB1)
    OR (foo.pk.idA = :idA2 AND foo.pk.idB = :idB2)
    OR (foo.pk.idA = :idA3 AND foo.pk.idB = :idB3)
    -- ...
)

But I'm sure you can see how ugly and unscalable this is.

I'm using Java 6/JPA 1/Hibernate 3

For what it's worth, I'm using Oracle, and I'm expecting the SQL generated to be something like:

-- This works fine in my database, assuming the schema contains the refered table and columns.
SELECT foo.ID_A, foo.ID_B
FROM Foo foo
WHERE (foo.ID_A, foo.ID_B) in ((?,?), (?,?), (?, ?))

Your can use the Criteria API to replace your hql .

// your list of FooPks
List<FooPk> pkList = ....

//Create a criteria over an entity
Criteria  criteria = session.createCriteria(Foo.class);
// add a restriction
criteria.add(Restrictions.in("pk", pkList));
// Execute query and get result.
List<Foo> foos = criteria.list();

The following worked for MySQL:

  1. Create a javax.persistence.NamedQuery for the @Entity

     @NamedQuery(name = "select", query = "SELECT foo FROM Foo foo WHERE foo.pk IN :pks") 
  2. Select via

     final TypedQuery<Foo> typedQuery = this.entityManager.createNamedQuery("select", Foo.class); final FooPK fooPk = new FooPK(...); // Create example FooPK typedQuery.setParameter("pks", Arrays.asList(fooPk, fooPk)); return typedQuery.getResultList(); 

The resulting SQL:

select ... from ... where foo0_.idA=? and foo0_.idB=? or foo0_.idA=? and foo0_.idB=?

(Note the two checks for each idA and idB )

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