使用 @ManyToMany 时出现 ***Error
Posted
技术标签:
【中文标题】使用 @ManyToMany 时出现 ***Error【英文标题】:***Error while using @ManyToMany 【发布时间】:2019-06-01 02:23:21 【问题描述】:在尝试和谷歌搜索类似问题几个小时后,我仍然无法解决问题:
我正在构建一个 sprint 启动应用程序(在 Kotlin 中),它使用 JPA(也包括休眠)和 H2(不认为它是相关的)。我想模拟用户和成就类之间的多对多关系(所以一个用户可以有多个成就,一个成就可以由多个用户实现)。以下是模型类:
@Entity
data class User(
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
val id: Int = 0,
@Column(nullable = false)
val name: String,
@ManyToMany(cascade = [ CascadeType.PERSIST, CascadeType.MERGE ])
val achievements: MutableSet<Achievement> = HashSet()
)
@Entity
data class Achievement(
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
val id: Int = 0,
val key: String,
@ManyToMany(mappedBy = "achievements")
val users: MutableSet<User> = HashSet()
)
我看到以下日志,这个模型似乎工作正常:
Hibernate: create table achievement (id integer not null, key varchar(255), priority integer not null, category_id integer, primary key (id))
Hibernate: create table user (id integer not null, name varchar(255) not null, primary key (id))
Hibernate: create table user_achievements (users_id integer not null, achievements_id integer not null, primary key (users_id, achievements_id))
然后我在@Service @Transactional 中预填充数据,如下所示:
val achievement = Achievement(key = "SOME_ACHIEVEMENT_KEY")
achievementRepository.save(achievement)
val user = User(name = "John Doe")
userRepository.save(user)
并添加关系:
val foundAchievement = achievementRepository.findById(achievementId)
val foundUser = userRepository.findById(userId)
foundAchievement.ifPresent achievement ->
foundUser.ifPresent user ->
user.achievements.add(achievement)
userRepository.save(user)
如果我现在尝试通过对以下 URL 之一执行 GET 来访问数据:
http://localhost:8080/achievements/2/users
http://localhost:8080/users/3/achievements
我得到一个 java.lang.***Error 并且日志显示 hibernate 试图一遍又一遍地查询成就和用户(无限循环,直到堆栈溢出)。
所以这是我的问题:
-
您知道为什么会出现此错误吗?
我的模型正确吗?
我将用户连接到成就的方式是否正确,或者我是否还需要将用户添加到成就中(或者甚至将整个内容保存在成就存储库中)?
【问题讨论】:
【参考方案1】:好的,问题是 Kotlin 的双向关系和自动生成的 equals() 和 hashCode() 的组合。
由于我使用的是 Kotlin 数据类,它会为主构造函数中定义的每个属性自动生成 hashCode() 和 equals()。我将 @ManyToMany 带注释的属性从主构造函数中取出,问题消失了:
@Entity
data class Achievement(
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
val id: Int = 0,
val key: String
)
@ManyToMany(mappedBy = "achievements")
val users: MutableSet<User> = HashSet()
@Entity
data class User(
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
val id: Int = 0,
@Column(nullable = false)
val name: String
)
@ManyToMany(cascade = [CascadeType.PERSIST, CascadeType.MERGE])
val achievements: MutableSet<Achievement> = HashSet()
【讨论】:
以上是关于使用 @ManyToMany 时出现 ***Error的主要内容,如果未能解决你的问题,请参考以下文章
在 httpd 中使用 ServerName 作为 www.example.com 时出现 ERR_TOO_MANY_REDIRECTS
读取智能卡时出现 ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED
运行 tkinter+pymysql 脚本时出现 pymysql.err.ProgrammingError
到达 Tomcat 时出现 ERR_CONNECTION_TIMED_OUT