在春季一对多实体关系不获取数据

Posted

技术标签:

【中文标题】在春季一对多实体关系不获取数据【英文标题】:In spring One To Many entity relationship is not fetching data 【发布时间】:2020-01-22 00:55:46 【问题描述】:

我有一个简单的场景,其中 UserSkill 之间存在关系, 意味着一个用户有很多技能,所以我尝试了:

用户

@Data
@NoArgsConstructor
@Entity
@EqualsAndHashCode
public class User 

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;     
    private String name;    
    @OneToMany(mappedBy = "user")
    private List<Skill> skills;


技能

@Data
@NoArgsConstructor
@Entity
@EqualsAndHashCode
public class Skill 
    
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;        
    private String skillTitle;      
    @ManyToOne
    @JoinColumn(name="user_id")
    private User user;


用户存储库

@RepositoryRestResource(collectionResourceRel = "users", path = "users")
public interface UserRepository extends PagingAndSortingRepository<User, Long> 
    List<User> findByName(@Param("name") String name);

技能库

@RepositoryRestResource(collectionResourceRel = "skills", path = "skills")
public interface SkillRepository extends CrudRepository<Skill, Long>
    

通过以上所有内容,我可以在例如 url http://localhost:8085/users/1 得到响应


    "name": "Root",
    "_links": 
        "self": 
            "href": "http://localhost:8085/users/1"
        ,
        "user": 
            "href": "http://localhost:8085/users/1"
        ,
        "skills": 
            "href": "http://localhost:8085/users/1/skills"
        
    

问题不是我不知道为什么没有获取技能列表,为什么只获取了这个

"skills": 
   "href": "http://localhost:8085/users/1/skills"

不是与user/1 相关的技能的完整列表。

更新

按照建议添加投影: 用户投影.java

@Projection(name = "inlineData", types=User.class)
public interface UserProjection 
    String getName();
    List<Skill> getSkills();

UserRepository.java 是

@RepositoryRestResource(collectionResourceRel = "users", path = "users", excerptProjection = UserProjection.class)
public interface UserRepository extends PagingAndSortingRepository<User, Long> 
    List<User> findByName(@Param("name") String name);

回复是:


    "name": "Root",
    "_links": 
        "self": 
            "href": "http://localhost:8085/users/1"
        ,
        "user": 
            "href": "http://localhost:8085/users/1?projection",
            "templated": true
        ,
        "skills": 
            "href": "http://localhost:8085/users/1/skills"
        
    

【问题讨论】:

你能把代码贴在你使用 findByUserId() 函数产生这个响应的地方吗? 这不就是 HATEOAS 的意义所在吗?点击链接可以看到用户的技能。 @CholNhial 单击该链接时不显示任何内容... 同样在 API 请求中,您正在发送 user1 但您正在为 user3 发布响应。 在第二个示例中,方法的名称是 findByUserId,但您将 skillId 作为参数传递。没事吧? 【参考方案1】:

响应是正确的,它按预期工作。 @RepositoryRestResource 遵循 HATEOAS 原则。 Spring documentation解释如下:

5.1.3。资源可发现性

HATEOAS 的核心原则是资源应该是可发现的 通过发布指向可用的链接的链接 资源...

通过向根 URL 发出请求...客户端可以从 返回的 JSON 对象,一组代表下一级的链接 客户端可用的资源...

您会获得代表资源的链接。要检索特定资源,您应该调用相应的 URL。您对用户 1 的回复意味着,如果您想获得用户 1 的技能,您应该调用 URL“http://localhost:8085/users/1/skills”。

如果您想象您有一个显示用户 1 属性的 html 页面,则更容易理解。此页面不直接显示技能,而是此页面包含指向技能页面的链接。只有当用户点击此链接时,才会加载技能页面。

了解HATEOAS很重要。

当然,有时 HATEOAS 不是最佳选择。但是这里我们不是在讨论 HATEOAS,而是解释 Spring 的这种实现背后的想法是什么。这种方法在许多情况下确实很有帮助。当您有 2 个具有 1-2 个属性的实体时,您可能会将这种方法视为矫枉过正。但是如果你有 30 - 50 个实体,每个实体有 3 - 5 个关系,每个关系包含 50 - 100 个其他实体,那么处理这样的数据模型可能会非常困难。而 HATEOAS 可以让它变得更容易。使用这种方法,您只是导航这些关系:加载一个实体、选择需要的关系、在这个关系上加载实体、选择需要的实体、在这个实体中选择需要的关系、加载这个关系或导航回其父实体通过父关系等。

【讨论】:

但是通过点击http://localhost:8085/users/1/skills链接我得到skills[]。有什么理由吗?

以上是关于在春季一对多实体关系不获取数据的主要内容,如果未能解决你的问题,请参考以下文章

获取核心数据中一对多关系的计数

IOS:通过一对多关系获取核心数据

快速获取具有一对多关系的核心数据

NSPredicate 用于从一对多关系中获取项目,不包括特定的相关实体

我可以在 Core Data 中获取关系数据吗

Core Data 获取一对多关系的数据