通过具有 ManyToOne 关系的实体上的 Hibernate 投影,在 SQL 查询中使用更少的列
我正在尝试构建一个较小的 SQL,以避免默认为 hibernate Criteria 构建的“select * from A”。
如果我使用简单的字段(没有关系),通过“Transformers”,我可以设法拥有这个 SQL:
select description, weight from Dog;
嗨,我有这个实体:
@Entity
public class Dog
{
Long id;
String description;
Double weight;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "person_id", nullable = false)
Person owner;
}
@Entity
public class Person
{
Long id;
String name;
Double height;
Date birthDate;
}
我的目标是拥有这个:
select description, weight, owner.name from Dog
我用 Criteria(和 subcriteria)尝试了这个:
Criteria dogCriteria = sess.createCriteria(Dog.class);
ProjectionList proList = Projections.projectionList();
proList.add(Projections.property("description"), description);
proList.add(Projections.property("weight"), weigth);
dogCriteria.setProjection(proList);
Criteria personCriteria = dogCriteria.createCriteria("owner");
ProjectionList ownerProList = Projections.projectionList();
ownerProList.add(Projections.property("name"), description);
dogCriteria.setProjection(ownerProList); //After this line, debugger shows that the
//projection on dogCriteria gets overriden
//and the query fails, because "name" is
//not a field of Dog entity.
如何我应该使用投影来获得更小的 SQL、更少的列吗? 提前致谢。
I'm trying to build a smaller SQL, to avoid the "select * from A" that is being build by default for hibernate Criteria.
If I use simple fields (no relation), through "Transformers", I have can manage to have this SQL:
select description, weight from Dog;
Hi, I have this Entity:
@Entity
public class Dog
{
Long id;
String description;
Double weight;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "person_id", nullable = false)
Person owner;
}
@Entity
public class Person
{
Long id;
String name;
Double height;
Date birthDate;
}
My goal is to have this:
select description, weight, owner.name from Dog
I tried this with with Criteria (and subcriteria):
Criteria dogCriteria = sess.createCriteria(Dog.class);
ProjectionList proList = Projections.projectionList();
proList.add(Projections.property("description"), description);
proList.add(Projections.property("weight"), weigth);
dogCriteria.setProjection(proList);
Criteria personCriteria = dogCriteria.createCriteria("owner");
ProjectionList ownerProList = Projections.projectionList();
ownerProList.add(Projections.property("name"), description);
dogCriteria.setProjection(ownerProList); //After this line, debugger shows that the
//projection on dogCriteria gets overriden
//and the query fails, because "name" is
//not a field of Dog entity.
How should I use Projections, to get a smaller SQL, less columns ?
Thanks in advance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
首先,
是无效的SQL。它必须是类似的东西
。其次,为什么?虽然可以做您想做的事情(见下文),但通过 Criteria API 执行此操作非常冗长,而且您没有任何收获。几列的数据传输节省可以忽略不计,除非所述列是巨大的 blob 或者您要选择数十万条记录。无论哪种情况,都有更好的方法来处理这个问题。
任何人,要执行您想要的条件,您需要通过别名加入链接表(人)并使用所述别名指定在 main 条件上的投影:
标准投影文档。请记住,执行时,上述条件将返回对象数组列表。您需要指定 ResultTransformer 以便将结果转换为实际对象。
First of all,
is not valid SQL. It would have to be something like
instead. Secondly, why? While it's possible to do what you want (see below), it's extremely verbose to do so via Criteria API and you gain nothing to show for it. Savings on data transfer for a couple of columns are negligible unless said columns are huge blobs or you're selecting hundreds of thousands of records. In either case there are better ways to deal with this issue.
Anywho, to do what you want for criteria, you need to join linked table (Person) via alias and specify projection on main criteria using said alias:
There's a description and an example of the above in Criteria Projections documentation. Keep in mind that, when executed, the above criteria would return a list of object arrays. You'll need to specify a ResultTransformer in order to have results converted into actual objects.
我自己还没有尝试过,但我认为您也可以在实体(Pojo)中使用另一个构造函数并将列传递到那里。
请参阅 https://www.thoughts-on-java.org/hibernate- best-practices/章节“1.2 Pojo”有详细说明。
但对我来说,还不清楚这是否也适用于多对一关系。我会尝试一下。
I didn't tried it yet by myself, but I think you can also use another constructor in your Entity (Pojo) and pass the columns there.
See https://www.thoughts-on-java.org/hibernate-best-practices/ chapter "1.2 Pojo" for a detailed instruction.
Altough for me it's not yet clear if this also works for ManyToOne relationships too. I will have a try.