jaetzold
jaetzold

Reputation: 1688

How to map two unidirectional relationships between two domains correctly?

I have two domain classes where i want a unidirectional relationship from each to the other:

class User {
    HistoryEntry lastFooEntry

    static constraints = {
        lastFooEntry(nullable: true)
    }
}
class HistoryEntry {
    String name
    User createdBy
}

According to the grails documentation (as i understand it) this is the way to do it. Specifying belongsTo would create a bidirectional relationship (what i don't want) and hasOne only works with bidirectional relationships anyway.

The problem with the above modelling is, that the following code only works when entryName=='foo'. For any other value the assertion is false:

def addHistoryEntry(Long id, String entryName) {
    def user = User.get(id)
    if(!user) {
        user = new User(id: id).save()
    }
    def entry = new HistoryEntry(createdBy: user, name: entryName).save()
    if(entryName=='foo') {
        user.lastFooEntry = entry
        user.save()
    } else {
        assert user.lastFooEntry!=entry
    }
}

I can work around this by specifying

static mappedBy = [createdBy:'']

in HistoryEntry. But according to IntelliJ IDEA and the grails documentation this should only be used in conjunction with hasMany and I've never seen it with an empty string.

So the question: What is the right way to do this? Or is it a undocumented feature / bug and my workaround is fine so far?

Upvotes: 0

Views: 380

Answers (1)

Victor Sergienko
Victor Sergienko

Reputation: 13475

If you don't specify a field on the other side of relationship, relationship will remain unidirectional in terms of JVM - i.e. your example is suffficient and you need nothing more. hasOne in User or/and belongsTo in HistoryEntry will also work.

The example is probably missing something, because the assertion cannot be false: the entry was just created, and never assigned to anything, so it's impossible for that User or any other object to reference it. Moreover, entry is not saved or flushed yet.

Whether a 1:1 relationship in relational database is 1-directional or 2-directional is more a question of interpretation: normally you only have foreign key only on one end, but the other way can also be calculated.

So don't worry, Grails will never auto-add a reference field on ther other end of a relationship unless you declare that field explicitly.

Upvotes: 1

Related Questions