简体   繁体   中英

In spring One To Many entity relationship is not fetching data

I have simple scenario where there is relation between User and Skill , means one user many skills, so I tried with:

User

@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;

}

Skill

@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;

}

UserRepository

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

SkillRepository

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

}

with all above I'm able to get response at for example 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"
        }
    }
}

not the issue is I'm not figuring out why list of skills is not fetched, why only this is fetched

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

not a full list of skills related to user/1 .

UPDATE

Added projection as suggested: UserProjection.java

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

UserRepository.java is

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

response is:

{
    "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"
        }
    }
}

The response is correct, it works as intended. @RepositoryRestResource follows HATEOAS principles. Spring documentation explains it as follows:

5.1.3. Resource Discoverability

A core principle of HATEOAS is that resources should be discoverable through the publication of links that point to the available resources...

By issuing a request to the root URL... the client can extract, from the returned JSON object, a set of links that represent the next level of resources that are available to the client...

You get links that represent resources. To retrieve specific resources you should call corresponding URL. Your response for User 1 means that if you want to get Skills of User 1 you should call URL " http://localhost:8085/users/1/skills ".

It is easier to understand it if you imagine that you have an HTML page that displays properties of User 1. This page does not directly display Skills, instead this page contains a link to Skills page. Only if a user clicks on this link the Skills page will be loaded.

It is important that you understand HATEOAS well.

Of course there can be cases when HATEOAS is not the best choice. But here we are not discussing HATEOAS, but explaining what is the idea behind this implementation of Spring. This approach can really be helpful in many cases. When you have 2 entities with 1-2 attributes, you may consider such approach as overkill. But if you have 30 - 50 entities, each with 3 - 5 relations, each relation containing 50 - 100 other entities, it can be quite hard to deal with such data model. And HATEOAS can make it much easier. With this approach you are just navigating these relations: load one entity, select needed relation, load entities on this relation, select needed entity, in this entity select needed relation, load this relation, or navigate back to its parent entity via parent relation, etc.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM