有没有办法将自定义对象包含为另一个自定义对象的内部对象? 例如,我有两个Entites:
@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]
可以这样做吗?
答案 0 :(得分:0)
尝试在new package.BarQueryResult(f.bars.id, f.bars.x)
之后删除逗号?
答案 1 :(得分:0)
请注意,JPA / Hibernate API结构用于操作数据库对象(实体)。如果您想操纵非实体,那么最好在JPA之外创建自己的自定义集合。
那就是说,你的Foo是你的Bar对象('many'侧)的父对象('one'侧),即孩子。你可以做四件事来获得你的FooQueryResult(即Foo'a'和Bars):
1)在Bar对象(foo_id)中添加父字段。基本上,child使用父级的主键(@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)用于构造所有对象的另一个对象,包括Bars:
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的所有Bars的查询:
@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;
}
答案 2 :(得分:0)
开箱即用是不可能的。你应该使用select new constructor expression,但是有一个限制 - 嵌套构造函数调用不受支持,你不能写select new FooQueryResult(..., new BarQueryResult)
或者您可以使用自定义ResultSetTransformer。但我建议创建Transformer类并手动完成。