繁体   English   中英

JPA / HIBERNATE:查询如何返回非实体对象或带有内部非实体对象的对象列表?

[英]JPA/HIBERNATE: How can Query return Non- Entities Objects or List of Objects with inner non-Entities objects?

有没有办法将一个自定义对象作为另一个自定义对象的内部对象包含在内? 例如,我有两个实体:

@Entity
class Foo {
    @Id
    private int id;

    @Column
    private String a;

    @Column
    private String b;

    @OneToMany(...)
    private Set<Bar> bars;

    ...
}

@Entity
class Bar {
    @Id
    private int id;

    @Column
    private String x;

    @Column
    private String y;

    @Column
    private String z;

    ...
}

我想编写一个查询,选择一个FooQueryResult对象,例如:

class FooQueryResult {
    private String a;
    private Set<BarQueryResult> bars;

    ...
}

class BarQueryResult {
    private String id;
    private String x;

    ...
}

我正在尝试以下内容

String query =
        "SELECT " +
                "s.a, " +
                "new package.BarQueryResult(f.bars.id, f.bars.x) " +
        "FROM Foo as f " +
        "WHERE f.id = ?1";

FooQueryResult site = factory.createEntityManager()
        .createQuery(query, FooQueryResult.class)
        .setParameter(1, fooId)
        .getSingleResult();

但这以错误结尾:

QuerySyntaxException: unexpected token: , near line 1, column 14 [SELECT s.a, new package.BarQueryResult(f.bars.id, f.bars.x) FROM package.Foo as f WHERE f.id = ?1]

有可能这样做吗?

尝试在new package.BarQueryResult(f.bars.id, f.bars.x)后删除逗号new package.BarQueryResult(f.bars.id, f.bars.x)吗?

请注意,存在用于处理数据库对象(实体)的JPA / Hibernate API结构。 如果要操纵非实体,则最好在JPA之外创建自己的自定义集合。

也就是说,您的Foo是Bar对象(“许多”侧)的父对象(“一个”侧),即子对象。 您可以通过执行以下四项操作来获取FooQueryResult(即Foo'a'和Bars):

1)在您的Bar对象(foo_id)中添加一个父字段。 基本上,孩子使用父级的主键(@Id)与父级联接。

2)在Bar对象上与父Foo建立多对一关系,即

@ManyToOne
  @JoinColumn(name="foo_id",
    referencedColumnName = "foo_id")
  private Foo foo;

3)创建FooQueryResult作为返回查询结果的对象,例如

public class FooQueryResult {
  private String a;
  private String b;
  private String x;
  private String y;
  private String z; ...

4)创建查询(此处直接在子对象中使用JPA的命名查询方法):

@Entity
@Table(name="Bar")
  @NamedQuery(name="Bar.FooQueryResult",
    query="SELECT NEW FooQueryResult("
    + "e.foo.a, e.foo.b, e.x, e.y, e.z)"
    + " FROM Bar e"
    + " WHERE e.foo.id = :foo_id") ...

最后,在您的Session bean中,您可以创建一个方法来返回结合了Foo和Bar对象的结果列表:

public List<FooQueryResult> myResults(int foo_id) {
    return em.createNamedQuery("Bar.FooQueryResult")
      .setParameter("foo_id", foo_id)
      .getResultList();
  }

这是您可以通过5个步骤实现所需目标的另一种方法:

1)创建Foo和聚合Bar对象的类。 其中包括两个构造函数:a)一个用于构造Foo对象的构造函数; b)用于构造所有对象的另一个对象,包括Bar:

public class FooQueryResult {
private a;
private b;
private List<BarResult> bars;

public FooQueryResult(a, b) ...
public FooQueryResult(a, b, List<Bar> bars) ...
...

2)创建另一个仅返回Bars的结果对象:

public class BarResult {
    private x
    private y
    private z
    ...

3)在Foo实体中,使用仅构建Foos的构造函数创建返回所需Foo对象的查询:

@Entity
@Table(name="Foo")
  @NamedQuery(name="Bar.FooQueryResult",
    query="SELECT NEW FooQueryResult("
    + "e.a, e.b)"
    + " FROM Foo e"
    ...

4)在Bar实体中,创建一个查询,该查询返回Foo的所有Bar:

@Entity
@Table(name="Bar")
  @NamedQuery(name="Bar.BarResult",
    query="SELECT NEW BarResult("
    + "e.x, e.y, e.z)"
    + " FROM Bar e"
    + " WHERE e.foo.id = :foo_id") ...

5)最后,创建一个返回聚合的方法:

public List<FooQueryResult> myResults() {
    List<FooQueryResult> aggregate;

        for (FooQueryResult foo : em.createNamedQuery("Foo.FooQueryResult")
          .getResultList()) {

          // create a new result
          FooQueryResult query = new FooQueryResult();
// add Foos
          query.setA(foo.getA());
          query.setB(foo.getB());

          // .. then add Bars
          query.setBars(em.createNamedQuery("Bar.BarResult")
          .setParameter("foo_id", foo.id)
          .getResultList());

            // add query to aggregate
            aggregate.add(query);
          }
    return aggregate;
}

开箱即用是不可能的。 您应该使用select new构造函数表达式,但是有一个限制-不支持嵌套构造函数调用,您不能编写select new FooQueryResult(..., new BarQueryResult)
或者您可以使用自定义的ResultSetTransformer。 但是我建议创建Transformer类并手动进行。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM