我必须为以下Oracle-SQL编写JPQL查询:
SELECT * FROM Foo f, Bar b, Xyz x WHERE f.id = b.foo(+) and f.id = x.foo(+) and (lower(f.label) like lower('%filter%') or lower(f.code) like lower('%filter%') or lower(b.label) like lower('%filter%') or lower(x.label) like ('%filter%');
有多个Bar和Xyz表,每个Bar / Xyz对都连接到Foo的子类:
@Entity
@Table(name = "FOO")
// JOINED doesn't work because of an EclipseLink error!
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "TP", discriminatorType = DiscriminatorType.STRING, length = 5)
public abstract class Foo extends AbstractEntity {
private static final long serialVersionUID = -9137682737124302402L;
@Column(name = "CODE", nullable = false, length = 40)
private String code;
@Column(name = "LABEL", nullable = false, length = 4000)
private String label;
//...other properties
}
@Entity
@Table(name = "ABCD")
@DiscriminatorValue("ABCD")
public class Abcd extends Foo {
private static final long serialVersionUID = 250474360860393393L;
@OneToMany(mappedBy = "abcd")
@OrderColumn(name = "IDX")
private List<Bar> barList;
@OneToMany(mappedBy = "abcd")
@OrderColumn(name = "IDX")
private List<Xyz> xyzList;
protected Abcd() {
this.barList = new ArrayList<Bar>();
this.xyzList = new ArrayList<Xyz>();
}
//...getter/setter
}
@Entity
@Table(name = "BAR")
public class Bar extends AbstractEntity {
private static final long serialVersionUID = 2628239098357340769L;
@ManyToOne(fetch = FetchType.EAGER, optional = false, cascade = CascadeType.ALL)
@JoinColumns({ @JoinColumn(name = "ABCD_ID", referencedColumnName = "ID", nullable = false) })
private Abcd abcd;
@Column(name = "LABEL", nullable = false, length = 4000)
private String label;
protected Bar() {
}
// ...getter/setter, some other properties
}
@Entity
@Table(name = "XYZ")
public class Xyz extends AbstractEntity {
private static final long serialVersionUID = 2628239098357350769L;
@ManyToOne(fetch = FetchType.EAGER, optional = false, cascade = CascadeType.ALL)
@JoinColumns({ @JoinColumn(name = "ABCD_ID", referencedColumnName = "ID", nullable = false) })
private Abcd abcd;
@Column(name = "LABEL", nullable = false, length = 4000)
private String label;
protected Xyz() {
}
// ...getter/setter, some other properties
}
@MappedSuperclass
public abstract class AbstractEntity {
private static final long serialVersionUID = -8574667350713432415L;
@EmbeddedId
private PersistId id;
public static boolean isId(PersistId id) {
return (id != null && id.getId() > 0);
}
public boolean hasId() {
return isId(getId());
}
public PersistId getId() {
return this.id;
}
public void setId(PersistId id) {
this.id = id;
}
}
PersistId封装了一个名为ID的列,该列当前实现为Long。正如我之前所说,还有一些Foo的其他子类,它们与Bar / Xyz等其他类相连。
如何在Eclipselink中实现SQL(使用Criteria API)?我测试了一些不同的东西,但我没有得到任何结果。我还使用子查询来获取与过滤器匹配的ABCD_ID,但是我遇到了与Foo和Abcd匹配的问题。我有两个方法,它们生成查询和过滤器参数。
private CriteriaQuery<Foo> getQuery() {
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Foo> query = criteriaBuilder.createQuery(Foo.class);
Root<Foo> foo = query.from(Foo.class);
query.select(foo);
query.distinct(true);
return query;
}
private CriteriaQuery<Foo> addFilter(CriteriaQuery<Foo> query, String fullTextFilter) {
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
Set<Root<?>> roots = query.getRoots();
Iterator<Root<?>> iter = roots.iterator();
Root<Foo> foo = (Root<Foo>) iter.next();
List<Predicate> criteria = new ArrayList<Predicate>();
if (fullTextFilter != null) {
ParameterExpression<String> p = criteriaBuilder.parameter(String.class, "filter");
Path<String> label = foo.<String>get("label");
Path<String> code = foo.<String>get("code");
// TODO: add some code to handle Bar and Xyz labels
criteria.add(criteriaBuilder.or(criteriaBuilder.like(criteriaBuilder.lower(label), criteriaBuilder.lower(p)),
criteriaBuilder.like(criteriaBuilder.lower(code), criteriaBuilder.lower(p))));
}
if (criteria.size() == 1) {
query.where(criteria.get(0));
}
if (criteria.size() > 1) {
query.where(criteriaBuilder.and(criteria.toArray(new Predicate[0])));
}
return query;
}
有什么想法吗?我想,我还没有理解Criteria API上的任何基本内容,你能用一些源代码来启发我吗?
由于 安德烈
答案 0 :(得分:0)
如果你可以允许加入Abcd表,那么查询应该在Abcd实体而不是Foo上,因为它与Xyz和Bar有关系。然后,您可以将Joining或fetch join添加到查询中:
CriteriaQuery<Abcd > query = criteriaBuilder.createQuery(Abcd.class);
Root<Abcd> foo = query.from(Abcd.class);
foo.fetch("barList", JoinType.LEFT);
foo.fetch("xyzList", JoinType.LEFT);
query.select(foo);
query.distinct(true);