Details
-
Type:
Sub-task
-
Status:
Closed
-
Priority:
Major
-
Resolution: Fixed
-
Affects Version/s: 1.0
-
Fix Version/s: 1.1-beta1
-
Component/s: Persistence
-
Labels:None
Description
Implementation Recommendations...
1) New syntax for the hasMany definition that allows multiple M2M relationships. Addition of a 'join' attribute that identifies the name of the relationship in the other DO. It would be ideal if 'join' was optional for DOs with only a single M2M relationship.
2) Join table is named based on the singularized concatonation of the two relationship names. The relationship name from the owning DO should be first.
3) FKs should be table + "_" + id.
There is a challange in that many databases limit table and column names to a certan number of characters (I believe in the case of Oracle it's 30).
Example:
class Book {
static hasMany [authors:[object:Person, join:books],
publishers:[object:Person, join:publishedBooks]]
static belongsTo = Person
}
class Person {
static hasMany [books:[object:Book, join:authors],
publishedBooks:[object:Book, join:publishers]]
}
This would generate 4 tables. 2 base DO tables (BOOK, PERSON) and 2 join tables (AUTHOR_BOOK, PUBLISHER_PUBLISHED_BOOK). Adding . Let's add some data so that we have the following, one book (book.id= 1) and two authors (person.id = 55 and person.id = 66) and a publisher (person.id = 77).
BOOK
| ID | NAME |
|---|---|
| 1 | Some Book |
PERSON
| ID | NAME |
|---|---|
| 55 | Sue |
| 66 | Jim |
| 77 | Matt |
AUTHOR_BOOK
| BOOK_ID | PERSON_ID |
|---|---|
| 1 | 55 |
| 1 | 66 |
PUBLISHER_PUBLISHED_BOOK
| BOOK_ID | PERSON_ID |
|---|---|
| 1 | 77 |
The following SQL would then work...
select book.name, person.name as author
from book, person, author_book
where book.id = author_book.book_id
and person.id = author_book.person_id
...resulting in the following...
| NAME | AUTHOR |
|---|---|
| Some Book | Sue |
| Some Book | Jim |
In re-reading this issue, it didn't seem entirely clear that in addition to enhancing the hasMany functionality, I am hoping that the default behavior is changed.
To anyone with a database design background, the current behavior is counterintuitive. As we see on the mailing list at least once a week someone posts their confusion with naming of the join table's foreign keys (and I agree it is confusing, the explanation in JIRA-828 notwithstanding). If Grails is trying to adhere to conventions this is a place where it currently misses the mark.
Using the following two classes and the BOOK/PERSON data from the issue description above, you would end up with a join table called PERSON_BOOK where the ID from the BOOK table is stored in a column called AUTHORS_ID and the ID from the PERSON table is stored in a column called BOOKS_ID. So in addition to the non-standard pluralization of the column name, the IDs in the join table appear reversed. Sure you could look at the constraints, but it could/should be clearer just looking at the column names.
class Person {
static hasMany = [books: Book]
}
class Book {
static hasMany = [authors:Person]
static belongsTo = Person
}
PERSON_BOOK (current counterintuitive behavior)
So my suggestion for the default behavior is when there is a single M2M, you would not need to specify the new object & join parameters, however you would get a join table like the following.
PERSON_BOOK