如何在Spring Boot中使用Hibernate / JPA返回多级json [英] How can I return multi-level json using Hibernate/JPA in Spring Boot

查看:153
本文介绍了如何在Spring Boot中使用Hibernate / JPA返回多级json的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Postgres数据库,有4个表父母,子女,团体和Group_Membership。

I have a Postgres Database that has 4 tables Parents, Children, Groups and Group_Membership.

群组可以拥有多个家长,家长可以拥有多个群组。父母可以有多个孩子,但孩子只能有一个孩子。

Groups can have multiple parents and Parents can have multiple groups. Parents can have multiple children but children can only have one parent.

这是架构的愚蠢版本。

This is the dumbed down version of the schema.

我正在使用Spring Boot和Hibernate JPA。

I am using Spring Boot with 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<Child> children;
    @ManyToMany(cascade = { CascadeType.ALL })
    @JoinTable(
            name= "Group_Membership",
            joinColumns = { @JoinColumn(name = "parent_id") },
            inverseJoinColumns = { @JoinColumn(name = "group_id") }
    )
    private Set<Group> 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<Parent> parents = new HashSet<>();

    //Constructor 
    //Getters and Setters
}

我有所有这些设置的存储库:

I have repositories for all of them set up like this:

public interface GroupRepository extends PagingAndSortingRepository<Group, Long> {
    @RestResource(rel = "name-contains", path = "containsName")
    Page<Group> 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

When I go to 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

Then when I want to look at the parents in the group I go to 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 / childr en

Finally when I want to see the children of the first parent in the group I go to 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

I would like to be able to call one endpoint like http://localhost:8080/groups/search/findAllGroupMembers?group_id=1

并拥有它返回组中的多级json,组中的所有父级以及每个父级的所有子级。

and have it return multi level json with the group, all parents in the group, and all of the children of each parent.

我知道如何使用子查询编写查询来返回此信息,但我只是好奇是否有更多的JPA / Hibernate方法来执行此操作?

I know how to write a query with sub-queries to return this information, but I was just curious if there is a more "JPA/Hibernate" way to do this?

谢谢!

编辑:修正使用Alan Hay的回答

GroupFullProjection.java

@Projection(name = "groupFullProjection", types = {Group.class})
public interface GroupFullProjection {
    Long getGroupId();
    String getName();
    Set<ParentFullProjection> getParents();
}

ParentFullProjection.java

@Projection(name = "parentFullProjection", types = {Parent.class})
public interface ParentFullProjection {
    Long getParentId();
    String getFirstName();
    String getLastName();
    Set<Child> getChildren();
}

json回复所有必填信息

端点: http:// localhost :8080 / groups / 1?projection = groupFullProjection

Endpoint: 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提供,并且了解它的外观以及如何更改它可能值得学习。

Lazy/Eager loading has absolutely nothing to do with it. The REST services in your application are provided by Spring Data Rest and having an understanding of why it looks like it does and how you can change it is probably worth learning.

https://docs.spring.io/spring-data/rest/docs/current/reference/html/#repository-resources.fundamentals

基本上,您可以获得指向关联的链接,因为这些实体拥有自己的存储库,这些存储库作为REST资源公开。如果孩子/父母没有作为REST资源公开,那么数据将被内联(因为没有其他方式可以访问它们)。

Essentially you get the links to the associations because these entities have their own repositories which are exposed as REST respources. If children/parent were not exposed as REST reources then the data would be inlined (as there would be no other way to access them).

但是你可以使用Projections获取数据的替代视图。因此,您可以定义一个内联关联的投影。客户可以请求此数据的特定视图。

You can however use Projections to fetch alternative views of the data. So you can then define a projection that would inline the assocations. Clients can request this specific view of the data.

例如。 http:// localhost:8080 / groups / 1?projection = groupFullProjection

这涉及创建一个简单的界面,用于定义要在该数据视图中公开的属性。

This involves creating a simple interface that defines the properties to be exposed in that view of the data.

请参阅:< a href =https://docs.spring.io/spring-data/rest/docs/current/reference/html/#projections-excerpts =nofollow noreferrer> https://docs.spring.io/ spring-data / rest / docs / current / reference / html / #project-摘录

这可能类似于:

@Projection(name = "parentFullProjecton", types = { Parent.class })
interface ParentFullProjection{

    // inline the child collection
    Set<Child> getChildren();

    // other fields
}

@Projection(name = "groupFullProjection", types = { Group.class })
interface GroupFullProjection{

    //inline the parents collection and use the view which inlines Children
    Set<ParentFullProjecton> getParent();

    // other fields
}

这篇关于如何在Spring Boot中使用Hibernate / JPA返回多级json的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆