JPQL等价物

时间:2013-02-12 11:13:16

标签: inheritance eclipselink jpql criteria-api

我必须为以下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上的任何基本内容,你能用一些源代码来启发我吗?

由于 安德烈

1 个答案:

答案 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);