【问题标题】:How to ensure true one-to-many relationship如何确保真正的一对多关系
【发布时间】:2012-11-10 07:44:39
【问题描述】:

我在实体之间存在一对多的关系 - RentalUnit 和 Review 。所有测试都运行良好,除非我向不同的 RentalUnit 实例添加相同的评论,如下所示:

def review3 = Review.build().save(flush: true)
def rentalUnit2 = RentalUnit.build().
    addToReviews(review2).addToReviews(review3).save(flush: true)
assert rentalUnit.reviews.contains(review2)

似乎 GORM 和 addTo* 方法似乎并不关心我是否添加了相同的 Review 实例,所以我猜我的域类中缺少一些东西。那会是什么?

感谢您的帮助

附言

class Review {
    String submittedBy
    String content
    String dateReceived
    boolean isApproved

    static belongsTo = RentalUnit

    static mapping = {
        content type: 'text'
    }

    static constraints = {
        submittedBy blank: false, size: 3..50
        content blank: false, size: 5..2500

    }
}

class RentalUnit {
    String name
    String nickname
    Address address
    static hasMany = [reviews:Review]

    static mapping = {
        reviews cascade: "all-delete-orphan"
    }

    static constraints = {
        name blank: false, unique: true, size: 4..10
        nickname blank: false, size: 5..60
    }
}

【问题讨论】:

    标签: grails grails-orm


    【解决方案1】:

    是的,它不在乎——它不会改变任何其他对象的属性。即使是关系的另一端——review2.rentalUnit(如果存在这样的字段)在这里也将为空。

    下次从数据库加载对象时,评论将从rentalUnit.reviews 中消失(或分配review2.rentalUnit)。

    您可以手动分配 review2.rentalUnit 并验证它是否已添加到另一个 RentalUnit,不过 - 分配不会造成任何伤害。

    编辑:让我们一步一步看代码。

    rentalUnit1.addToReviews(review2)
    

    这里将review2 添加到rentalUnit1.reviewsreview2.rentalUnit 没有被分配,但是在保存到数据库中之后它会指向rentalUnit1RentalUnit.reviews 字段的唯一持久表示是子到父引用字段Review.rentalUnit

    def rentalUnit2 = ...
    rentalUnit2.addToReviews(review2).addToReviews(review3).save(flush: true)
    

    这里将review2 添加到rentalUnit2.reviewsreview2.rentalUnit 不会再次分配。 review2 不会从rentalUnit1.reviews 中删除,但是保存后,在数据库中,它将指向rentalUnit2

    assert rentalUnit1.reviews.contains(review2)
    

    review2 没有从rentalUnit1.reviews 中删除,因此断言将通过。但是在下一个会话中,rentalUnit1rentalUnit2 将拥有正确的 reviews 集 - 只有 rentalUnit2 将拥有 review2

    现在,如果您想始终保持 Java 表示的一致性,请实现如下方法:

    class RentalUnit {
        RentalUnit addToReviewsAndCheck(Review r) {
             if (r.rentalUnit == this) return;
             if (r.rentalUnit != null) {
                 r.rentalUnit.removeFromReviews(r)
             }
             r.rentalUnit = this
             addToReviews(r)
        }
    }
    

    但对我来说,这太过分了。

    【讨论】:

    • 谢谢维克多。请纠正我,但这意味着它在物理上不是真正的一对多关系,因为同一个评论在物理上引用了两个不同的 RentalUnits(如果共享评论被更新,它会更新两个不同的 RentalUnits 评论的集合)。因此,要实现真正的一对多关系,我们必须检查是否在另一个出租单元中没有引用要为特定 RentalUnit 添加的评论......因为是否有任何内置机制(即约束等)或者我们手动遍历每个 RentalUnit.reviews 集合,这可能非常昂贵......
    • 在物理上,RentalUnitReview 中只有一个引用。 belingsTo 创建一个隐式字段 Review.rentalUnit,您可以检查它 (grails.org/doc/latest/ref/Domain%20Classes/belongsTo.html)。希望我的问题是正确的。
    • 谢谢维克多。我很感激。英语不是我的第一语言,所以我很抱歉自己无法清楚地表达。从 RentalUnit 到 Review 的一对多关系 == 从 Review 到 RentalUnit 的多对一关系,对吗?但是,特定的共享 Review 指向多个 RentalUnit,除非我们在将 Review 添加到 RentalUnit 时手动强制执行。这有意义吗?我的理性有错误吗?...谢谢
    • 没关系,我相信我没听错,就像你描述的那样。我看不到Review 指向多个RentalUnit 的任何物理可能性,belongsTo 只创建一个字段。因此,您要查找的问题必须是添加到两个RentalUnitreviews 集合中的问题,对吗?那么所有的答案都是一样的——没关系,下次会恢复现状。
    • 是的,维克多。相同的评论被添加到两个不同的 RentalUnits。此共享评论(如果更新)反映了两个 RentalUnits.reviews 集合的更改...因此,即使您没有参考共享评论对两个出租单元中的任何一个,它也与两个出租单元相关...
    猜你喜欢
    • 2021-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多