我想使用规范将过滤器/搜索应用于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位于共享超类中有关,也与静态元模型有关吗?