使用JPA Criteria API

时间:2015-08-20 08:15:28

标签: hibernate jpa criteria metamodel

我想使用规范将过滤器/搜索应用于Spring Data存储库。构建谓词时,如果在多对多结果集上进行子选择,则会选择错误的实体ID。 我使用生成的JPA Metamodel,Id保存在两个连接实体的超类中。

这是规范:

    public class KontaktSpecification implements Specification<Kontakt> {

    private final KontaktSearchObject kontaktSearchObject;

    public KontaktSpecification(KontaktSearchObject kontaktSearchObject) {
        this.kontaktSearchObject = kontaktSearchObject;
    }

    @Override
    public Predicate toPredicate(Root<Kontakt> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
        List<Predicate> predicates = new ArrayList<Predicate>();            

        if (kontaktSearchObject.getGruppeId() != null) {
            Subquery<Integer> sq = query.subquery(Integer.class);       
            ListJoin<Kontakt, Gruppe> join = sq.from(Kontakt.class).join(Kontakt_.gruppen);
            sq.select(join.get(Kontakt_.id));

            Predicate paramPredicate = cb.equal(join.get(Gruppe_.id), kontaktSearchObject.getGruppeId());

            sq.where(paramPredicate);

            predicates.add(cb.in(root.get(Kontakt_.id)).value(sq));
        }

        if(kontaktSearchObject.getArchiv() != null) {
            predicates.add(cb.equal(root.get(Kontakt_.archiv), kontaktSearchObject.getArchiv().toString()));
        }   

        return cb.and(predicates.toArray(new Predicate[]{}));
    }

}

Kontakt实体的摘录:

    @Entity
    @Table(name = "kontakt", uniqueConstraints = @UniqueConstraint(columnNames = "emailAdresse"))
    public class Kontakt extends AbstractModifiableEntity {
    .
    .
    .
        @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
        @JoinTable(name = "kontakt_gruppe", uniqueConstraints = @UniqueConstraint(columnNames = {"gruppeID", "kontaktID" }), joinColumns = { @JoinColumn(name = "kontaktID", nullable = false, updatable = false) }, inverseJoinColumns = { @JoinColumn(name = "gruppeID", nullable = false, updatable = false) })
        @OrderBy("name")
        @BatchSize(size = 30)   
        public synchronized List<Gruppe> getGruppen() {
            return this.gruppen;
        }
    }

Gruppe实体的摘录:

    @Entity
    @Table(name = "gruppe")
    public class Gruppe extends AbstractEntity {
    .
    .
    .
        @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
        @JoinTable(name = "kontakt_gruppe", uniqueConstraints = @UniqueConstraint(columnNames = { "gruppeID",
        "kontaktID" }) , joinColumns = {
                @JoinColumn(name = "gruppeID", nullable = false, updatable = false) }, inverseJoinColumns = {
                        @JoinColumn(name = "kontaktID", nullable = false, updatable = false) })
        @BatchSize(size = 40)
        public Set<Kontakt> getKontakts() {
            return this.kontakts;
        }
    }

AbstractEntity(AbstractModifiableEntity扩展AbstractEntity并使用@MappedSuperclass注释):

@MappedSuperclass
public abstract class AbstractEntity implements Serializable {
    private static final long serialVersionUID = 1L;

    protected Integer id;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", unique = true, nullable = false)
    public Integer getId() {
        return this.id;
    }

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

元模型:

KONTAKT _:

@Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor")
@StaticMetamodel(Kontakt.class)
public abstract class Kontakt_ extends de.chamaeleon.jnewsletter.model.entities.AbstractModifiableEntity_ {
    public static volatile SingularAttribute<Kontakt, String> strasse;
    public static volatile SingularAttribute<Kontakt, String> vorname;
    public static volatile SingularAttribute<Kontakt, Anrede> anrede;
    public static volatile SingularAttribute<Kontakt, Boolean> bestaetigt;
    public static volatile SetAttribute<Kontakt, AttributKontakt> attributKontakts;
    public static volatile SingularAttribute<Kontakt, String> fremdschluessel;
    public static volatile SingularAttribute<Kontakt, String> emailAdresseInternal;
    public static volatile ListAttribute<Kontakt, KontaktEreignis> kontaktEreignisse;
    public static volatile SetAttribute<Kontakt, MailVersand> mailVersands;
    public static volatile SingularAttribute<Kontakt, String> adminLogin;
    public static volatile SingularAttribute<Kontakt, String> ort;
    public static volatile SingularAttribute<Kontakt, String> institution;
    public static volatile SingularAttribute<Kontakt, String> password;
    public static volatile ListAttribute<Kontakt, MailEreignis> versandEreignisse;
    public static volatile SingularAttribute<Kontakt, Boolean> archiv;
    public static volatile SingularAttribute<Kontakt, String> nachname;
    public static volatile SingularAttribute<Kontakt, String> land;
    public static volatile SingularAttribute<Kontakt, MailFormat> mailFormat;
    public static volatile ListAttribute<Kontakt, Gruppe> gruppen;
    public static volatile SingularAttribute<Kontakt, String> einwilligungstext;
    public static volatile ListAttribute<Kontakt, NewsletterKategorie> kategorien;
    public static volatile SingularAttribute<Kontakt, String> plz;

}

GRUPPE _:

@Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor")
@StaticMetamodel(Gruppe.class)
public abstract class Gruppe_ extends de.chamaeleon.jnewsletter.model.entities.AbstractEntity_ {

    public static volatile SetAttribute<Gruppe, Kontakt> kontakts;
    public static volatile SetAttribute<Gruppe, TempAuthentifizierungGruppe> tempAuthentifizierungGruppes;
    public static volatile SingularAttribute<Gruppe, String> name;
    public static volatile SingularAttribute<Gruppe, Boolean> archiv;
    public static volatile SingularAttribute<Gruppe, Boolean> published;
    public static volatile SingularAttribute<Gruppe, String> fremdschluessel;
    public static volatile SetAttribute<Gruppe, MailVersand> mailVersands;

}

AbstractEntity _:

@Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor")
@StaticMetamodel(AbstractEntity.class)
public abstract class AbstractEntity_ {

    public static volatile SingularAttribute<AbstractEntity, Integer> id;

}

预期(或想要的)查询是(选择kontakt1_.id):

select count(kontakt0_.id) as col_0_0_
from kontakt kontakt0_
where kontakt0_.id in (
    select kontakt1_.id 
    from kontakt kontakt1_ 
        inner join kontakt_gruppe gruppen2_ on kontakt1_.id=gruppen2_.kontaktID 
        inner join gruppe gruppe3_ on gruppen2_.gruppeID=gruppe3_.id 
    where gruppe3_.id=431
)

但实际查询是(选择gruppe3_.id):

select count(kontakt0_.id) as col_0_0_
from kontakt kontakt0_
where kontakt0_.id in (
    select gruppe3_.id
    from kontakt kontakt1_ 
        inner join kontakt_gruppe gruppen2_ on kontakt1_.id=gruppen2_.kontaktID 
        inner join gruppe gruppe3_ on gruppen2_.gruppeID=gruppe3_.id 
    where gruppe3_.id=431
)

为什么?它是否与Id位于共享超类中有关,也与静态元模型有关吗?

0 个答案:

没有答案