一卷旌收千骑虏,万全身出百重围。这篇文章主要讲述JPA OneToMany,如何在控制台或webapp中打印时忽略字段ManyToOne相关的知识,希望能为你提供帮助。
我有2个表:流派(genre_id,genre_name)和电影(movie_id,movie_name,movie_score,genre_id)。 genre_id_fk来自类型中引用genre_id的电影。
@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<
>
();
}
第二个电影实体
@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;
}
当我尝试使用此代码在控制台中打印它时:
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);
}
接收
Exception in thread "main" java.lang.StackOverflowError
只删除电影类字段“genres”中的toString()可以修复它。但是有可能避免它吗?和春季启动应用程序相同的问题@RestController
public class GenreController {@Autowired
private GenreService genreService;
@RequestMapping("/test/{id}")
public List<
Genre>
getGenreInfo(@PathVariable int id){
return genreService.getGenreFilms(id);
}
}
在这里服务
@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;
}
}
【JPA OneToMany,如何在控制台或webapp中打印时忽略字段ManyToOne】并收到这样的问题:[{“id”:1,“name”:“Thriller”,“movies”:[{“id”:1,“name”:“Any,你还好吗?”,“得分” :5.45,“genre”:{“id”:1,“name”:“Thriller”,“movies”:[{“id”:1,“name”:“Any,你还好吗?”,“得分” :5.45,“genre”:{“id”:1,“name”:“Thriller”,“movies”:[{“id”:1,“name”:“Any,你还好吗?”,“得分” :5.45,“流派”:......和无限,有异常。控制台我可以通过忽略toString()方法中的字段来修复。但是如何在webapplication中解决这个问题呢?
这里是控制台打印时的hibernate调试日志
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
告诉我我在哪里做错了以及如何解决或谷歌这个问题?只是不能通过localhost:8080 / genre / id打印这个对象?制作特定的印刷品或什么?
答案当你尝试
toString
你的Genre
实体时,你似乎有无限的递归。您的代码首先按id加载您的Genre实体,然后调用Genre.toString()
。因为你与@OneToMany
s有Movie
关系,所以lazy loads
列表然后为每个与该类型相关的电影调用Movie.toString()
。然后,对于每部电影,你都会与流派有@ManyToOne
关系。这就是问题所在。它将再次为列表中的每部电影调用Genre.toString()
。可能的解决方案
- 如果您只想在控制台中打印它,请不要在
Genre.toString()
中包含电影列表 - 如果您正在使用杰克逊,请将
@JsonBackReference
添加到您在@ManyToOne
的Movie
关系中,这样杰克逊在映射到Json Annotation documentation here时会忽略它 - 如果使用DTO,请不要在DTO中包含
Movie
属性。
推荐阅读
- 我们可以配置要在Tomcat的webapp目录中的相应位置部署的文件夹吗()
- 我可以在界面上使用@MappedSuperclass注释吗()
- 找不到模块(无法解析'C: Userstestcounter-appsrc'中的'bootstrap / dist / css / bootstrap.cs(代码片)
- 使用Realm Swift Pod的APP无法运行(CMD + R,崩溃编译Realm)但它确实测试(CMD + U)并且还存档
- IE 11浏览器在尝试访问App Cached离线页面时显示“您未连接到网络”页面
- 从网站中提取Applet的源文件
- Xamarin App在调试时运行但在发布时崩溃
- 如何在Xamarin的新“Android设备管理器”中禁用快速启动()
- Xamarin Android在方向改变上保持内容