:: ORIGINAL :: (以下更新)
我有以下内容(简体):
@Entity(name = "Group")
@Table(name = "groups")
data class Group(
@Column
override val name: String,
) : CoreGroup {
@GeneratedValue
@Id
val id: Long = 0
@Transient
private val _users = mutableSetOf<User>()
@ManyToMany(cascade = [CascadeType.PERSIST, CascadeType.MERGE])
override val users get() = _users
}
结果表具有预期的name
和id
列,但未创建我期望的联接表(groups_users
)。如果我删除了后备属性,而只是将users
设置为普通属性,它将按预期工作。
我也尝试过对该属性进行@get:@ManyToMany...
,这没有任何效果。
如果我将注释放在backing属性上,则:
@ManyToMany(cascade = [CascadeType.PERSIST, CascadeType.MERGE])
private val _users = mutableSetOf<User>()
override val users get() = _users
这将创建联接表,但它称为groups__users
(双下划线),外键列称为_user_id
。在匹配的User
类中,我还必须使该属性引用backing属性,例如:@ManyToMany(mappedBy="_users")
我尝试在后备属性上使用@Column(name="user")
,它似乎被忽略了。
为什么实际属性不生成联接表?
:: UPDATED ::
看来问题的原因在于在方法而不是字段上使用注释。一个更简单的测试用例:
@Entity
class TestEntity {
@Id
@GeneratedValue
private val id: Long? = null
@OneToMany
private val otherEntity: Set<OtherEntity> = setOf()
}
这将按预期生成联接表。但是,这不是:
@Entity
class TestEntity {
@Id
@GeneratedValue
private val id: Long? = null
@OneToMany
fun getOtherEntity(): Set<OtherEntity> {
return emptySet()
}
}
据我了解,这些应该等效吗?该示例很好地演示了该问题,因为在原始示例中,使用@get:OneToMany
显然将注释放在了生成的get方法上。
我对这些注释或Hibernate的理解有问题吗?
答案 0 :(得分:0)
好的,所以我认为这是Kotlin的问题,但是当我用Java编写代码时发现同样的问题。最终,我发现您不能混合使用Hibernate的字段和方法注释。
在文档(RTFM ...)中:
2.2.2.2. Access type
默认情况下,类的访问类型 等级由位置定义 @Id或@EmbeddedId批注。 如果这些注释在字段上, 那么仅考虑字段 持久性和状态被访问 通过现场。如果有注释 在吸气剂上,然后只有吸气剂 被认为具有持久性, 状态通过 吸气剂/设定器。那在 练习并推荐 方法。
注意
注释在类层次结构中的位置必须一致 (无论是在字段上还是在财产上) 能够确定默认访问权限 类型。建议坚持 一个注解放置 整个策略 应用。
对于我的特定问题,在Kotlin中使用backing属性,然后必须使用@Access
注释,如下所示:
@Transient
private val _users = mutableSetOf<User>()
@get:ManyToMany(cascade = [CascadeType.PERSIST, CascadeType.MERGE])
@get:Access(AccessType.PROPERTY)
override val users get() = _users
private fun setUsers(users: Set<User>) {...}
不幸的是,这意味着我必须实现一个私有的setter。