我有两个域类 -Account
和Member
,并且我无法找到关联和mappedBy
属性的正确组合来建模它们的关系。用简单的英语来说,anAccount
需要一个且只有一个主要成员。它也有 0 - 许多家属。我最初的尝试看起来像:
Account.groovy
class Account {
String displayId
Member primaryMember
SortedSet<Member> dependents = new TreeSet<Member>()
static belongsTo = [Member]
static hasMany = [dependents: Member]
}
成员.groovy
class Member implements Comparable<Member> {
MemberType memberType = MemberType.PRIMARY
String firstName
String lastName
static belongsTo = [account: Account]
@Override
int compareTo(Member m) {
return (this.memberType <=> m?.memberType) * 100 + (this.lastName <=> m?.lastName) * 10 + (this.firstName <=> m?.firstName)
}
}
当我尝试实例化和持久化帐户和成员时,这会导致问题。例如,
AccountIntegrationTests.groovy
class AccountIntegrationTests extends GroovyTestCase {
Account smiths
Member john
Member jane
@Before
void setup() {}
@Test
void testShouldLoadAccountWithNoDependents() {
// Arrange
smiths = new Account(displayId: "ABCDEFG")
john = new Member(firstName: "John", lastName: "Smith", memberType: MemberType.PRIMARY)
smiths.primaryMember = john
smiths.save(flush: true, failOnError: true)
def smithsId = smiths.id
smiths.discard()
// Act
def loadedSmiths = Account.get(smithsId)
// Assert
assert loadedSmiths.members.size() == 1
assert loadedSmiths.primaryMember == john
assert loadedSmiths.dependents.size() == 0
}
@Test
void testShouldLoadAccountWithOneDependent() {
// Arrange
smiths = new Account(displayId: "ABCDEFG")
john = new Member(firstName: "John", lastName: "Smith", memberType: MemberType.PRIMARY)
smiths.primaryMember = john
smiths.addToDependents(new Member(firstName: "Jane", lastName: "Smith", memberType: MemberType.DEPENDENT))
smiths.save(flush: true, failOnError: true)
john = smiths.primaryMember
jane = smiths.dependents.first()
def smithsId = smiths.id
smiths.discard()
// Act
def loadedSmiths = Account.get(smithsId)
// Assert
assert loadedSmiths.members.size() == 2
assert loadedSmiths.primaryMember.firstName == "john"
assert loadedSmiths.dependents.size() == 1
assert loadedSmiths.dependents.first().firstName == "jane"
}
}
将抛出异常,因为第二个测试的数据库表看起来像
帐户
id | display_id
1 | ABCDEFG
成员
id | first_name | last_name | member_type | account_id
1 | John | Smith | Primary | 1
2 | Jane | Smith | Dependent | 1
显然我希望帐户检索 John 作为主要成员,Jane 作为依赖,但是当 GORM 尝试加载 account.primaryMember 时,它会抛出一个 Hibernate 异常,即有多个行(在成员中)匹配帐户 ID(1 )。我需要一个mappedBy
鉴别器来区分这两个关联,但是我尝试过的版本不起作用:
帐户
static mappedBy = [primaryMember: 'primaryMember', dependents: 'dependents']
- or -
static mappedBy = [dependents: 'account']
我已经阅读了关联的 GORM 文档mappedBy
,以及网站上关于同一模型的多个关联的各种 问题,不幸的是,它们似乎都在为多个关联建模。确实将一对多和一对一关系都引用到同一模型的那个将其说明为:hasMany
class Person {
String name
static belongsTo = [team: Team]
}
class Team {
String name
static belongsTo = [coach: Person]
static hasMany = [players: Person]
}
但是,我尝试使用这个简单的实现并得到:
--Output from testShouldLoadAccountWithNoDependents--
| Failure: testShouldLoadAccountWithNoDependents(AccountIntegrationTests)
| org.springframework.dao.InvalidDataAccessApiUsageException: object references an unsaved transient instance - save the transient instance before flushing: Account; nested exception is org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: Account
at AccountIntegrationTests.testShouldLoadAccountWithNoDependents(AccountIntegrationTests.groovy:26)
Caused by: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: Account
... 1 more
AccountIntegrationTests.groovy:26
是行smiths.save(flush: true, failOnError: true)
。当我将Team/Account
课程修改为:
class Team {
String name
Person coach
static hasMany = [players: Person]
}
我遇到了同样的异常,所以我相信某种cascade
是必需的。我尝试添加cascade
一个Account
:
帐户
static mapping = {
primaryMember cascade: 'all'
dependents cascade: 'all-delete-orphan'
}
然后我也尝试使用事件触发器:
帐户
def beforeInsert() {
if (primaryMember?.isDirty()) {
primaryMember.save()
}
}
def beforeUpdate() {
if (primaryMember?.isDirty()) {
primaryMember.save()
}
}
不幸的是,这些方法都没有解决transient instance
异常。非常感谢您对此的任何帮助。