Grails

One-to-one (bidirectional) does not currently produce correct data structure

Details

  • Type: Sub-task Sub-task
  • Status: Closed Closed
  • Priority: Critical Critical
  • Resolution: Fixed
  • Affects Version/s: 1.0.4
  • Fix Version/s: 1.1-beta2
  • Component/s: Persistence
  • Labels:
    None

Description

As shown from the sample app attached, Grails does not create an optimal (and only correct) data structure for a bidirectional one-to-one.

Grails creates two foreign key columns. One on the owning side, one on the non owning side. This is strange - Hibernate for this case only creates one foreign key column on the owner side, and clearly you only need one column.

Grails should be fixed so that it does not add the useless column on the non owner side (it is the one which is set nullable and that caused me problems; the right FK column on the owner side is marked as non nullable and is OK).

In the attached sample app, two classes are present in two versions, one pure GORM and one Hibernate. Look at the differences in the tables generated.

Also, maybe in the case of a one-to-one bidirectional the "unique" constraint should be applied automatically. Currently it's not the case (so nothing prevents a many to one actually).

Activity

Hide
Max Lapshin added a comment -

This feature is required because has_one associations meets often in Rails app. If we want to have possibility to seamlesly port applications to Grails, this is musthave feature

Show
Max Lapshin added a comment - This feature is required because has_one associations meets often in Rails app. If we want to have possibility to seamlesly port applications to Grails, this is musthave feature
Hide
Graeme Rocher added a comment -

Fixed. Not this fix applies only to bidirectional one-to-ones. A unidirectional one-to-one is still mapped as a many-to-one by default. You can make it unique if you don't like this, which results in a true one-to-one:

class Face {
    Nose nose

    static mapping = {
        nose unique:true
    }
}
Show
Graeme Rocher added a comment - Fixed. Not this fix applies only to bidirectional one-to-ones. A unidirectional one-to-one is still mapped as a many-to-one by default. You can make it unique if you don't like this, which results in a true one-to-one:
class Face {
    Nose nose

    static mapping = {
        nose unique:true
    }
}
Hide
David Rosenstark added a comment -

I downloaded 1.1 RC1 and groovy 1.6 and create two classes:

class Face {
String eyes;
String mouth;
Nose nose

static mapping = { nose unique:true }
}

class Nose {
Face face
String nostril1
String nostril2

}

When i bring up the app, i still see two foreign key columns:
alter table face add constraint FK2FD65D7F0070FA foreign key (nose_id) references nose
alter table nose add constraint FK33AFD3BF056CBA foreign key (face_id) references face

Show
David Rosenstark added a comment - I downloaded 1.1 RC1 and groovy 1.6 and create two classes: class Face { String eyes; String mouth; Nose nose static mapping = { nose unique:true } } class Nose { Face face String nostril1 String nostril2 } When i bring up the app, i still see two foreign key columns: alter table face add constraint FK2FD65D7F0070FA foreign key (nose_id) references nose alter table nose add constraint FK33AFD3BF056CBA foreign key (face_id) references face
Hide
Graeme Rocher added a comment -

In order to get the single column mapping you need to define an owner:

class Face {
String eyes;
String mouth;
Nose nose

static mapping = { nose unique:true }
}

class Nose { 
   static belongsTo [face:Face] // THIS IS THE CHANGE
   String nostril1 
   String nostril2 
}

Sorry should have been clear on that in the issue

Show
Graeme Rocher added a comment - In order to get the single column mapping you need to define an owner:
class Face {
String eyes;
String mouth;
Nose nose

static mapping = { nose unique:true }
}

class Nose { 
   static belongsTo [face:Face] // THIS IS THE CHANGE
   String nostril1 
   String nostril2 
}
Sorry should have been clear on that in the issue
Hide
David Rosenstark added a comment -

Thanks, for the clarification. If i understand what you are saying (and i tested it and it works!), then this means that we in order to have the one FK, we are forced to have the cascade in this direction and not the reverse. In other words, if the FK were in Nose instead, then Face would need to belongTo Nose and cascading would be reversed. Or is there some way around this?

Show
David Rosenstark added a comment - Thanks, for the clarification. If i understand what you are saying (and i tested it and it works!), then this means that we in order to have the one FK, we are forced to have the cascade in this direction and not the reverse. In other words, if the FK were in Nose instead, then Face would need to belongTo Nose and cascading would be reversed. Or is there some way around this?
Hide
Rohan Machado added a comment -

This above trick to attain bidirectional one-to-one association works great. Many thanks.

Is it possible to set this up without "belongsTo" - more specifically, I want to avoid the cascaded deletion that occurs due to belogsTo, but still use bidirectioanl one-to-one.

I agree, I can always use the One-to-Many to get around it.

Show
Rohan Machado added a comment - This above trick to attain bidirectional one-to-one association works great. Many thanks. Is it possible to set this up without "belongsTo" - more specifically, I want to avoid the cascaded deletion that occurs due to belogsTo, but still use bidirectioanl one-to-one. I agree, I can always use the One-to-Many to get around it.
Hide
Graeme Rocher added a comment -

Bulk closing bunch of resolved issues

Show
Graeme Rocher added a comment - Bulk closing bunch of resolved issues

People

Vote (7)
Watch (6)

Dates

  • Created:
    Updated:
    Resolved: