简体   繁体   中英

JpaRepository findAll() is fetching nested objects

I searched about this problem the whole morning and I couldn't get a valid solution.

I have the following code:

@Entity
@Getter
@Setter
@ToString
@EqualsAndHashCode
@Table(name = Tag.TABLE_NAME)
@NoArgsConstructor
public class Tag {
  static final String TABLE_NAME = "blog_tags";
  private static final String ID_TAG = "idTag";
  private static final String FIELD_TAG = "tag";
  private static final String FK_POST = "FK_Post";

  @Id
  @NotNull
  @Column(name = ID_TAG, unique = true)
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;

  @NotNull
  @Column(name = FIELD_TAG, unique = true)
  private String tagName;

  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = FK_POST, insertable = false, updatable = false)
  private Post post;

  @NotNull
  @Column(name = FK_POST)
  private Long fkPost;

}

The entity Post also has a JPA @OneToMany annotation with a mappedBy and fetch LAZY.

However, when I use the default method findAll/findOne to retrieve my tags it also makes a select to retrieve posts.

What can I do to only retrieve the three fields of the Tag Entity without making a custom query? I want to use the methods provided by JpaRepository.

Thanks in advance.

Edit: Post Entity

@Entity
@NoArgsConstructor
@Table(name = Post.TABLE_NAME)
public class Post {
  static final String POST_AUTHOR_ENTITYGRAPH = "Post.author";
  private static final String MAPPED_BY_POST = "post";
  static final String TABLE_NAME = "blog_posts";
  private static final String FIELD_POST_VISITS = "post_visits";
  private static final String FIELD_POST_MODIFIED = "post_modified";
  private static final String FIELD_POST_ENABLED = "post_enabled";
  private static final String FIELD_POST_DATE = "post_date";
  private static final String FIELD_POST_CONTENT = "post_content";
  private static final String FIELD_COMMENTS_ENABLED = "comments_enabled";
  private static final String FIELD_TITLE = "post_title";
  private static final String ID_POST = "idPost";
  private static final String FK_AUTHOR = "FK_Author";

  @NotNull
  @Column(name = FIELD_COMMENTS_ENABLED)
  private boolean commentsEnabled;

  @NotNull
  @Column(name = FIELD_POST_CONTENT, columnDefinition = "LONGTEXT")
  private String postContent;

  @NotNull
  @Column(name = FIELD_POST_DATE, unique = true, columnDefinition = "DATETIME")
  private LocalDateTime postDate;

  @NotNull
  @Column(name = FIELD_POST_ENABLED)
  private boolean postEnabled;

  @Id
  @Column(name = ID_POST, unique = true)
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;

  @NotNull
  @Column(name = FIELD_POST_MODIFIED, columnDefinition = "DATETIME")
  private LocalDateTime postModified;

  @NotNull
  @Column(name = FIELD_TITLE, unique = true)
  private String postTitle;

  @NotNull
  @Column(name = FIELD_POST_VISITS)
  private Long postVisits;

  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = FK_AUTHOR, insertable = false, updatable = false)
  private User author;

  @NotNull
  @Column(name = FK_AUTHOR)
  private Long fkAuthor;

  @ManyToMany(fetch = FetchType.LAZY)
  @JoinTable(name = "blog_posts_categories", joinColumns = @JoinColumn(name = ID_POST, referencedColumnName = ID_POST), //
      inverseJoinColumns = @JoinColumn(name = Category.ID_CATEGORY, referencedColumnName = Category.ID_CATEGORY))
  private Set<Category> categories;

  @OneToMany(mappedBy = MAPPED_BY_POST, fetch = FetchType.LAZY)
  private Set<Image> images;

  @OneToMany(mappedBy = MAPPED_BY_POST, fetch = FetchType.LAZY)
  private Set<Tag> tags;

 // Autogenerated getters & setters

  @Override
  public String toString() {
    return "Post [commentsEnabled=" + commentsEnabled + ", postContent=" + postContent
        + ", postDate=" + postDate + ", postEnabled=" + postEnabled + ", id=" + id
        + ", postModified=" + postModified + ", postTitle=" + postTitle + ", postVisits="
        + postVisits + "]";
  }

Edit: Added TagController

@Api(tags = "Tags")
@RestController
@RequestMapping(TagController.REST_API)
public class TagController {

  static final String REST_API = "/tags";
  public static final String ID_TAG = "ID_TAG";
  public static final String PARAM_URL = "/{" + ID_TAG + "}";

  private final JpaRepository<Tag,Long> repository;
  private final TagMapper mapper;

  @Autowired
  TagController(final JpaRepository<Tag,Long> repository,
      final TagMapper mapper) {
    this.repository = repository;
    this.mapper = mapper;
  }

  @ApiOperation(value = "Find all the tags from database.", tags = "tags")
  @GetMapping(produces = "application/json")
  public List<TagDto> getAllTags() {
    return mapper.entityToDtoList(repository.findAll());
  }

}

SQL OUTPUT

Hibernate: select tag0_.idTag as idTag1_6_, tag0_.FK_Post as FK_Post2_6_, tag0_.tag as tag3_6_ from blog_tags tag0_
Hibernate: select post0_.idPost as idPost1_3_0_, post0_.FK_Author as FK_Autho3_3_0_, post0_.comments_enabled as comments2_3_0_, post0_.post_content as post_con4_3_0_, post0_.post_date as post_dat5_3_0_, post0_.post_enabled as post_ena6_3_0_, post0_.post_modified as post_mod7_3_0_, post0_.post_title as post_tit8_3_0_, post0_.post_visits as post_vis9_3_0_ from blog_posts post0_ where post0_.idPost=?
Hibernate: select user0_.idUser as idUser1_7_0_, user0_.user_email as user_ema2_7_0_, user0_.passwordHash as password3_7_0_, user0_.FK_Role as FK_Role8_7_0_, user0_.passwordSalt as password4_7_0_, user0_.user_enabled as user_ena5_7_0_, user0_.user_name as user_nam6_7_0_, user0_.user_website as user_web7_7_0_ from blog_user user0_ where user0_.idUser=?
Hibernate: select userrole0_.idUserRole as idUserRo1_8_0_, userrole0_.user_role as user_rol2_8_0_ from blog_user_roles userrole0_ where userrole0_.idUserRole=?

Edit:

After looking over the code once more, it's possible that another part of the application is attempting to get your Post 's. Calling the getter for Post will tell Hibernate to fetch the entity.

This can sometimes happen even if you're not explicitly invoking the getter. Jackson may be calling it when attempting to write your response or it could even be invoked through a call to toString . For example, if you're looking at this response at a breakpoint in your IDE it's possible that your IDE's debugger is invoking toString behind the scenes in order to populate the debugger UI with your object's info.

It's likely Jackson is invoking your Post getter when serializing your List<Tag> response to JSON. Your may want to try adding the correct Jackson JSON parser to support Hibernate datatypes.

https://github.com/FasterXML/jackson-datatype-hibernate

For example, try adding the datatype to your pom

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-hibernate5</artifactId>
</dependency>

And adding a bean for the correct module.

@Bean
public Module hibernateModule() {
    return new Hibernate5Module();
}

You should take a look and make sure you're using the correct module for your version of Hibernate.

thank you very much for your answers. Finally I could resolve the problem.

It actually resided in the pom configuration, I forgot to delete a plugin related to Hibernate that, I don't know why, forced hibernate to fetch the nested objects.

Thank you everyone for helping me.

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