Question

I have one-to-many relationship between entities - RentalUnit and Review . All tests run fine, except when i am adding the same review to different RentalUnit instances as following:

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

It seems that GORM and the addTo* method doesn't seem to care if i am adding the same Review instance, so i am guessing there is something missing in my domain classes. What would that be?

Thank you for helping

p.s.

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
    }
}
Was it helpful?

Solution

Yes it doesn't care - it doesn't change any other objects' properties. Even about the other end of relationship - review2.rentalUnit (if such field existed) will be null here.

The Review will disappear from rentalUnit.reviews (or review2.rentalUnit would be assigned) the next time the object is loaded from database.

You can assign review2.rentalUnit by hand and validate if it's been added to another RentalUnit, though - the assignment will do no harm.

edit: let's go through the code step-by-step.

rentalUnit1.addToReviews(review2)

Here review2 is added to rentalUnit1.reviews. review2.rentalUnit is NOT assigned, but after save in the database it would point to rentalUnit1. The only persistent representation of RentalUnit.reviews field is a child-to-parent reference field, Review.rentalUnit.

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

Here review2 is added to rentalUnit2.reviews. review2.rentalUnit is NOT assigned again. review2 is NOT removed from rentalUnit1.reviews BUT, after save, in the database, it will point to rentalUnit2.

assert rentalUnit1.reviews.contains(review2)

review2 was NOT removed from rentalUnit1.reviews, so the assertion will pass. BUT in the next session rentalUnit1 and rentalUnit2 will have the correct sets of reviews - only rentalUnit2 will have review2.

Now, if you want to always maintain Java representation consistent, implment a method like this:

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

but it's an overkill, as for me.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top