如何在Spring Boot中使用Hibernate / JPA返回多级json
我有一个Postgres数据库,有4个表父母,子女,团体和Group_Membership。
群组可以有多个父母,父母可以有多个群组。 父母可以有多个孩子,但孩子只能有一个孩子。
这是架构的愚蠢版本。
我正在使用Spring Boot和Hibernate JPA。
Parent.java
@Entity @Table(name = "parents") public class Parent { @Id @GeneratedValue @Column(name="parent_id") private Long parentId; @Column(name= "first_name") private String firstName; @Column(name= "last_name") private String lastName; @OneToMany(mappedBy="parent") private Set children; @ManyToMany(cascade = { CascadeType.ALL }) @JoinTable( name= "Group_Membership", joinColumns = { @JoinColumn(name = "parent_id") }, inverseJoinColumns = { @JoinColumn(name = "group_id") } ) private Set groups = new HashSet(); //Constructor //Getters and Setters }
Child.java
@Entity @Table(name = "children") public class Child { @Id @GeneratedValue @Column(name= "child_id") private Long childId; @Column(name= "first_name") private String firstName; @Column(name= "last_name") private String lastName; @ManyToOne @JoinColumn(name="parent_id", nullable=false) private Parent parent; //Constructor //Getters and Setters }
Group.java
@Entity @Table(name = "groups") public class Group { @Id @GeneratedValue @Column(name= "group_id") private Long groupId; private String name; @ManyToMany(mappedBy = "groups") private Set parents = new HashSet(); //Constructor //Getters and Setters }
我有所有这些设置的存储库:
public interface GroupRepository extends PagingAndSortingRepository { @RestResource(rel = "name-contains", path = "containsName") Page findByNameContains(@Param("name") String name, Pageable page); }
集团成员表
CREATE TABLE GROUP_MEMBERSHIP ( PARENT_ID INT NOT NULL, GROUP_ID INT NOT NULL, PRIMARY KEY (PARENT_ID, GROUP_ID), CONSTRAINT GROUP_MEMBERSHIP_IBFK_1 FOREIGN KEY (PARENT_ID) REFERENCES PARENTS (PARENT_ID), CONSTRAINT GROUP_MEMBERSHIP_IBFK_2 FOREIGN KEY (GROUP_ID) REFERENCES GROUPS (GROUP_ID) );
当我去http:// localhost:8080 / groups
我收到了这个回复:
{ "_embedded": { "groups": [ { "name": "Hyde Park", "_links": { "self": { "href": "http://localhost:8080/groups/1" }, "group": { "href": "http://localhost:8080/groups/1" }, "parents": { "href": "http://localhost:8080/groups/1/parents" } } } ] }, "_links": { "self": { "href": "http://localhost:8080/groups" }, "profile": { "href": "http://localhost:8080/profile/groups" }, "search": { "href": "http://localhost:8080/groups/search" } }, "page": { "size": 20, "totalElements": 1, "totalPages": 1, "number": 0 } }
然后当我想看看小组中的父母时,我会去http:// localhost:8080 / groups / 1 / parents
响应
{ "_embedded": { "parents": [ { "firstName": "Cherice", "lastName": "Giannoni", "_links": { "self": { "href": "http://localhost:8080/parents/1" }, "parent": { "href": "http://localhost:8080/parents/1" }, "groups": { "href": "http://localhost:8080/parents/1/groups" }, "children": { "href": "http://localhost:8080/parents/1/children" } } }, { "firstName": "Aylmer", "lastName": "Feckey" "_links": { "self": { "href": "http://localhost:8080/parents/2" }, "parent": { "href": "http://localhost:8080/parents/2" }, "groups": { "href": "http://localhost:8080/parents/2/groups" }, "children": { "href": "http://localhost:8080/parents/2/children" } } } ] }, "_links": { "self": { "href": "http://localhost:8080/groups/1/parents" } } }
最后,当我想看到小组中第一个父母的孩子时,我会去http:// localhost:8080 / parents / 1 / children
响应
{ "_embedded": { "children": [ { "firstName": "Richard", "lastName": "Giannoni" "_links": { "self": { "href": "http://localhost:8080/children/2" }, "child": { "href": "http://localhost:8080/children/2" }, "parent": { "href": "http://localhost:8080/children/2/parent" } } }, { "firstName": "Deeanne", "lastName": "Giannoni" "_links": { "self": { "href": "http://localhost:8080/children/1" }, "child": { "href": "http://localhost:8080/children/1" }, "parent": { "href": "http://localhost:8080/children/1/parent" } } } ] }, "_links": { "self": { "href": "http://localhost:8080/parents/1/children" } } }
我希望能够调用一个端点,如http:// localhost:8080 / groups / search / findAllGroupMembers?group_id = 1
并让它返回组中的多级json,组中的所有父母以及每个父母的所有孩子。
我知道如何使用子查询编写查询以返回此信息,但我只是好奇是否有更多“JPA / Hibernate”方法来执行此操作?
谢谢!
编辑:修复使用Alan Hay的答案
GroupFullProjection.java
@Projection(name = "groupFullProjection", types = {Group.class}) public interface GroupFullProjection { Long getGroupId(); String getName(); Set getParents(); }
ParentFullProjection.java
@Projection(name = "parentFullProjection", types = {Parent.class}) public interface ParentFullProjection { Long getParentId(); String getFirstName(); String getLastName(); Set getChildren(); }
json回复所有必需的信息
端点: http:// localhost:8080 / groups / 1?projection = groupFullProjection
{ "name": "Hyde Park", "groupId": 1, "parents": [ { "children": [ { "firstName": "Richard", "lastName": "Giannoni", }, { "firstName": "Deeanne", "lastName": "Giannoni", } ], "parentId": 1, "firstName": "Cherice", "lastName": "Giannoni", "_links": { "self": { "href": "http://localhost:8080/parents/1{?projection}", "templated": true }, "groups": { "href": "http://localhost:8080/parents/1/groups" }, "children": { "href": "http://localhost:8080/parents/1/children" } } }, { "children": [ { "firstName": "Hanson", "lastName": "Feckey", } ], "parentId": 2, "firstName": "Aylmer", "lastName": "Feckey", "_links": { "self": { "href": "http://localhost:8080/parents/2{?projection}", "templated": true }, "groups": { "href": "http://localhost:8080/parents/2/groups" }, "children": { "href": "http://localhost:8080/parents/2/children" } } } ], "_links": { "self": { "href": "http://localhost:8080/groups/1" }, "group": { "href": "http://localhost:8080/groups/1{?projection}", "templated": true }, "parents": { "href": "http://localhost:8080/groups/1/parents" } } }
Lazy / Eager加载与它完全无关。 应用程序中的REST服务由Spring Data Rest提供,并且了解它的外观以及如何更改它可能值得学习。
基本上,您可以获得指向关联的链接,因为这些实体具有自己的存储库,这些存储库作为REST资源公开。 如果未将子/父作为REST资源公开,那么数据将被内联(因为没有其他方法可以访问它们)。
但是,您可以使用Projections来获取数据的替代视图。 因此,您可以定义一个内联关联的投影。 客户端可以请求此特定数据视图。
例如http:// localhost:8080 / groups / 1?projection = groupFullProjection
这涉及创建一个简单的接口,该接口定义要在该数据视图中公开的属性。
请参阅: https : //docs.spring.io/spring-data/rest/docs/current/reference/html/#projections-excerpts
这看起来像是这样的:
@Projection(name = "parentFullProjecton", types = { Parent.class }) interface ParentFullProjection{ // inline the child collection Set getChildren(); // other fields } @Projection(name = "groupFullProjection", types = { Group.class }) interface GroupFullProjection{ //inline the parents collection and use the view which inlines Children Set getParent(); // other fields }
- Hibernate分页机制
- 错误:不推荐使用PersistenceProvider,使用HibernatePersistenceProvider而不是HibernatePersistence
- 如何使用Hibernate和Spring Boot正确处理空结果集
- Hibernateexception_ $$ _ javassist_0无法强制转换为javassist.util.proxy.Proxy
- Spring MVC,从请求生成表单支持对象?
- 如何在Hibernate Criteria中添加Distinct
- Hibernate:在调用save()之前必须手动分配此类的ID
- 为hibernate 3.6配置pom.xml
- 使用Hibernate OGM进行MongoDb身份validation