首页 文章

与Grails中相同域类的一对一和一对多关联

提问于
浏览
0

我有两个域类 - AccountMember ,我无法找到正确的关联组合和 mappedBy 属性来建模它们的关系 . 简单来说, Account 需要一个且只有一个主要成员 . 它也有0个很多家属 . 我最初的尝试看起来像:

Account.groovy

class Account {
    String displayId

    Member primaryMember
    SortedSet<Member> dependents = new TreeSet<Member>()

    static belongsTo = [Member]
    static hasMany = [dependents: Member]
}

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异常,即有多个行(在Member中)与帐户ID匹配(1 ) . 我需要一个 mappedBy 鉴别器来区分这两个关联,但我尝试过的版本不起作用:

帐户

static mappedBy = [primaryMember: 'primaryMember', dependents: 'dependents']
- or -
static mappedBy = [dependents: 'account']

我已经阅读了关联和mappedBy的GORM文档,以及the site上的various questions关于multiple associationssame model,不幸的是它们似乎都在建模多个 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:26smiths.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 异常 . 非常感谢对此提供的任何帮助 .

1 回答

  • 0

    令人尴尬的简单解决方案是从 Member 中删除 static belongsTo = [account: Account] . 双向关联导致了这些问题 .

相关问题