0

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

谢谢安德烈

4

1 回答 1

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);
于 2013-02-12T15:46:44.047 回答