简体   繁体   English

JPA OneToMany,在控制台或Webapp中打印时如何忽略字段ManyToOne

[英]JPA OneToMany , how to ignore field ManyToOne when print in console or webapp

I have 2 tables: genres(genre_id, genre_name) and movies (movie_id, movie_name, movie_score, genre_id). 我有2个表格:类型(genre_id,genre_name)和电影(movie_id,movie_name,movie_score,genre_id)。 genre_id_fk from movies referenced to genre_id in genres. 风格中引用genre_id的电影中的genre_id_fk。

@Entity
@Table(name = "genres", schema = "test")
public class Genre {

@Id
@Column(name = "genre_id")
private int id;
@Column(name = "genre_name")
private String name;
@OneToMany(mappedBy = "genre", fetch = FetchType.LAZY)
private List<Movie> movies = new ArrayList<>();
}

and 2nd entity for movies 电影的第二实体

@Entity
@Table(name = "movies", schema = "test")
public class Movie {

@Id
@GeneratedValue
@Column(name = "movie_id")
private int id;
@Column(name = "movie_name")
private String name;
@Column(name = "movie_score")
private double score;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "genre_id")
private Genre genre;
}

when i am trying to print it in console with this code: 当我尝试使用此代码在控制台中打印时:

public static void main(String[] args) {
    EntityManagerFactory emf = Persistence.createEntityManagerFactory("pu");
    EntityManager em = emf.createEntityManager();
    Genre genre = em.find(Genre.class, 1);
    System.out.println(genre);
}

receiving Exception in thread "main" java.lang.StackOverflowError only removing from toString() in movie class field "genres" can fix it. 仅在电影类字段“类型”中的toString()中删除,才能Exception in thread "main" java.lang.StackOverflowError接收到Exception in thread "main" java.lang.StackOverflowError可以解决该问题。 But is it possible to avoid it? 但是有可能避免吗? And same problem with spring boot application 和Spring Boot应用程序相同的问题

@RestController
public class GenreController {

@Autowired
private GenreService genreService;

@RequestMapping("/test/{id}")
public List<Genre> getGenreInfo(@PathVariable int id){
    return genreService.getGenreFilms(id);
}
}

here service 这里服务

@Service
public class GenreService {

public List<Genre> getGenreFilms(int id){
    EntityManagerFactory emf = Persistence.createEntityManagerFactory("pu");
    EntityManager em = emf.createEntityManager();
    List<Genre> genres = new ArrayList<>();
    Genre genre = em.find(Genre.class, id);
    genres.add(genre);
    return genres;
}
}

and receiving this problem like: [{"id":1,"name":"Thriller","movies":[{"id":1,"name":"Any, are you ok?","score":5.45,"genre":{"id":1,"name":"Thriller","movies":[{"id":1,"name":"Any, are you ok?","score":5.45,"genre":{"id":1,"name":"Thriller","movies":[{"id":1,"name":"Any, are you ok?","score":5.45,"genre":.... and to infinity with sof exception. 并收到以下问题:[{“ id”:1,“ name”:“ Thriller”,“ movies”:[{“ id”:1,“ name”:“好吗?”,“得分” :5.45,“类型”:{“ id”:1,“名称”:“惊悚片”,“电影”:[{“ id”:1,“名称”:“任何,你还好吗?”,“得分” :5.45,“类型”:{“ id”:1,“名称”:“惊悚片”,“电影”:[{“ id”:1,“名称”:“任何,你还好吗?”,“得分” :5.45,“ genre”:....并无穷无尽。 Console i can fix just with ignoring field in toString() method. 控制台我可以通过忽略toString()方法中的字段来解决。 But how to fix this problem in webapplication? 但是如何在Web应用程序中解决此问题?

here hibernate debug log when console print 在控制台打印时,这里是休眠调试日志

22:15:37.154 [main] DEBUG org.hibernate.engine.internal.TwoPhaseLoad - 
Resolving associations for [com.company.Genre#1]
22:15:37.164 [main] DEBUG org.hibernate.engine.internal.TwoPhaseLoad - Done 
materializing entity [com.company.Genre#1]
22:15:37.164 [main] DEBUG 
org.hibernate.resource.jdbc.internal.ResourceRegistryStandardImpl - 
HHH000387: ResultSet's statement was not registered
22:15:37.165 [main] DEBUG 
org.hibernate.loader.entity.plan.AbstractLoadPlanBasedEntityLoader - Done 
entity load : com.company.Genre#1
22:15:37.165 [main] DEBUG 
org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl - 
Initiating JDBC connection release from afterTransaction
22:15:37.167 [main] DEBUG org.hibernate.loader.collection.plan.AbstractLoadPlanBasedCollectionInitializer 
- Loading collection: [com.company.Genre.movies#1]
22:15:37.167 [main] DEBUG org.hibernate.SQL - select movies0_.genre_id as 
genre_id4_1_0_, movies0_.movie_id as movie_id1_1_0_, movies0_.movie_id as 
movie_id1_1_1_, movies0_.genre_id as genre_id4_1_1_, movies0_.movie_name as 
movie_na2_1_1_, movies0_.movie_score as movie_sc3_1_1_ from test.movies 
movies0_ where movies0_.genre_id=?
Hibernate: select movies0_.genre_id as genre_id4_1_0_, movies0_.movie_id as 
movie_id1_1_0_, movies0_.movie_id as movie_id1_1_1_, movies0_.genre_id as 
genre_id4_1_1_, movies0_.movie_name as movie_na2_1_1_, movies0_.movie_score 
as movie_sc3_1_1_ from test.movies movies0_ where movies0_.genre_id=?
22:15:37.168 [main] DEBUG 
org.hibernate.loader.plan.exec.process.internal.ResultSetProcessorImpl - 
Preparing collection intializer : [com.company.Genre.movies#1]
22:15:37.170 [main] DEBUG 
org.hibernate.loader.plan.exec.process.internal.ResultSetProcessorImpl - 
Starting ResultSet row #0
22:15:37.171 [main] DEBUG org.hibernate.loader.plan.exec.process.internal.CollectionReferenceInitializerIm 
pl - Found row of collection: [com.company.Genre.movies#1]
22:15:37.171 [main] DEBUG 
org.hibernate.loader.plan.exec.process.internal.ResultSetProcessorImpl - 
Starting ResultSet row #1
22:15:37.172 [main] DEBUG org.hibernate.loader.plan.exec.process.internal.CollectionReferenceInitializerIm 
pl - Found row of collection: [com.company.Genre.movies#1]
22:15:37.172 [main] DEBUG 
org.hibernate.loader.plan.exec.process.internal.ResultSetProcessorImpl - 
Starting ResultSet row #2
22:15:37.172 [main] DEBUG org.hibernate.loader.plan.exec.process.internal.CollectionReferenceInitializerIm 
pl - Found row of collection: [com.company.Genre.movies#1]
22:15:37.172 [main] DEBUG org.hibernate.engine.internal.TwoPhaseLoad - 
Resolving associations for [com.company.Movie#1]
22:15:37.172 [main] DEBUG org.hibernate.engine.internal.TwoPhaseLoad - Done 
materializing entity [com.company.Movie#1]
22:15:37.173 [main] DEBUG org.hibernate.engine.internal.TwoPhaseLoad - 
Resolving associations for [com.company.Movie#2]
22:15:37.173 [main] DEBUG org.hibernate.engine.internal.TwoPhaseLoad - Done 
materializing entity [com.company.Movie#2]
22:15:37.173 [main] DEBUG org.hibernate.engine.internal.TwoPhaseLoad - 
Resolving associations for [com.company.Movie#3]
22:15:37.173 [main] DEBUG org.hibernate.engine.internal.TwoPhaseLoad - Done 
materializing entity [com.company.Movie#3]
22:15:37.173 [main] DEBUG 
org.hibernate.engine.loading.internal.CollectionLoadContext - 1 collections 
were found in result set for role: com.company.Genre.movies
22:15:37.173 [main] DEBUG 
org.hibernate.engine.loading.internal.CollectionLoadContext - Collection 
fully initialized: [com.company.Genre.movies#1]
22:15:37.173 [main] DEBUG 
org.hibernate.engine.loading.internal.CollectionLoadContext - 1 collections 
initialized for role: com.company.Genre.movies
22:15:37.173 [main] DEBUG 
org.hibernate.resource.jdbc.internal.ResourceRegistryStandardImpl - 
HHH000387: ResultSet's statement was not registered
22:15:37.173 [main] DEBUG org.hibernate.loader.collection.plan.AbstractLoadPlanBasedCollectionInitializer 
- Done loading collection
Exception in thread "main" java.lang.StackOverflowError

tell me where i am doing wrong and how to fix or google this problem? 告诉我我在哪里做错了,以及如何解决或谷歌这个问题? just not print this object by localhost:8080/genre/id? 只是不通过localhost:8080 / genre / id打印此对象? make something particular print or what? 做一些特别的印刷品或什么?

It seems like you have an infinite recursion when trying toString your Genre entities. 好像你想的时候有一个无限循环toString您的Genre实体。 Your code first loads your Genre entity by id, and then calls Genre.toString() . 您的代码首先通过id加载您的Genre实体,然后调用Genre.toString() Because you have @OneToMany relationship with Movie s, it lazy loads the list and then calls Movie.toString() for every movie related to the genre. 因为您与Movie具有@OneToMany关系,所以它会lazy loads列表,然后为与该流派相关的每个电影调用Movie.toString() Then for every movie you have a @ManyToOne relationship back with Genre. 然后,对于每部电影,您都与Genre有@ManyToOne关系。 And here lies the problem. 问题就在这里。 It will call again Genre.toString() for each movie in the list. 它将为列表中的每个电影再次调用Genre.toString()

Possible solutions 可能的解决方案

  1. If you only want to simply print it in console, do not include movies list in Genre.toString() 如果只想在控制台中简单地打印它,则不要在Genre.toString()包括电影列表。
  2. If you are using Jackson, add @JsonBackReference to your @ManyToOne relationship in Movie , this way Jackson will ignore it when mapping to Json Annotation documentation here 如果您使用的是Jackson,请将@JsonBackReference添加到Movie@ManyToOne关系中,这样,当Jackson映射到此处的 Json Annotation文档时,Jackson将忽略它
  3. If using DTOs, just do not include Movie property in your DTO. 如果使用DTO,则不要在DTO中包含Movie属性。

Hope this helps. 希望这可以帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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