Grails 如何确保真正的一对多关系

Grails 如何确保真正的一对多关系,grails,gorm,Grails,Gorm,我在实体之间有一对多的关系——RentalUnit和Review。所有测试都可以正常运行,除非我将相同的审阅添加到不同的RentalUnit实例中,如下所示: def review3 = Review.build().save(flush: true) def rentalUnit2 = RentalUnit.build(). addToReviews(review2).addToReviews(review3).save(flush: true) assert rentalUnit.r

我在实体之间有一对多的关系——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实例,所以我猜我的域类中缺少了一些东西。那会是什么

谢谢你的帮助

p、 美国


是的,它不在乎-它不会更改任何其他对象的属性。即使是关系的另一端-
review2.rentalUnit
(如果该字段存在)在此处也将为空

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

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

编辑:让我们一步一步地浏览代码

rentalUnit1.addToReviews(review2)
此处
review2
被添加到
rentalUnit1.reviews
review2.未分配rentalUnit
,但在数据库中保存后,它将指向
rentalUnit1
RentalUnit.reviews
字段的唯一持久表示形式是子到父引用字段
Review.RentalUnit

def rentalUnit2 = ...
rentalUnit2.addToReviews(review2).addToReviews(review3).save(flush: true)
此处
review2
添加到
rentalUnit2.reviews
<代码>查看2。未再次分配rentalUnit
review2
不会从
rentalUnit1中删除。reviews
但是,保存后,在数据库中,它将指向
rentalUnit2

assert rentalUnit1.reviews.contains(review2)
review2
未从
rentalUnit1.reviews中删除,因此断言将通过。但是在下一个会话中,
rentalUnit1
rentalUnit2
将具有正确的
review
s集-只有
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)
    }
}

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

谢谢你,维克多。请纠正我,但这意味着它在物理上不是真实的一对多关系,因为同一评论在物理上引用了两个不同的RentalUnit(如果共享评论被更新,它将更新两个不同的RentalUnits评论的集合)。因此,为了实现真正的一对多关系,我们必须检查将要为特定RentalUnit添加的审查是否未在另一个租赁单元中引用…因为是否存在任何内置机制(即约束等),或者我们手动遍历每个RentalUnit。审查收集可能非常昂贵…物理上,
Review
中只有一个对
RentalUnit
的引用
belingsTo
创建一个隐式字段,
Review.rentalUnit
,您可以检查它()。希望我没弄错你的问题。谢谢你,维克多。我很感激。英语不是我的第一语言,所以我很抱歉不能清楚地表达自己。从RentalUnit到Review的一对多关系==从Review到RentalUnit的多对一,对吗?然而,特定的共享审查指向不止一个RentalUnit,除非我们在向RentalUnit添加审查时手动强制执行。这有意义吗?我的理性中有错误吗?…没关系,我相信你是对的,就像你描述的那样。我看不出有任何物理上的可能性让
审查
指向多个
RentalUnit
以下只创建一个字段。因此,您要查找的问题一定是添加到两个
RentalUnit
评论
集合中的问题,对吗?然后所有的答案都是一样的——没关系,在下一次会议上会恢复现状。是的,维克托。相同的审查被添加到两个不同的RentalUnit。如果更新,此共享评论将反映两个租赁单元的更改。评论集合…因此,即使共享评论未提及两个租赁单元中的任何一个,它也与两个租赁单元关联。。。
class RentalUnit {
    RentalUnit addToReviewsAndCheck(Review r) {
         if (r.rentalUnit == this) return;
         if (r.rentalUnit != null) {
             r.rentalUnit.removeFromReviews(r)
         }
         r.rentalUnit = this
         addToReviews(r)
    }
}