In Grails, a UniDirectional 1:M relationship uses a join table by default. See: http://grails.org/doc/2.3.7/guide/GORM.html#oneToMany
Why is this?
And is there anyway to stop this behaviour.
Thanks
To avoid the join table in unidirectional 1:M, foreign key has to be specified in the parent for the associations:
class Book {
static hasMany = [authors: Author]
static mapping = {
authors column: 'BOOK_AUTHOR_ID'
}
}
Related
I have two classes. For simplicity, I removed unrelated data. I need join Order to Survey not vice-versa.
I know that I can run
select * from Order o right join order.survey s where s.id='x'
However, it is not what I would like to do. I would like to join Order to Survey with left outer join, but the survey doesn't have an instance of Order class in the class. The order holds an instance of the survey class, that's why it is easier to join tables from order class. I did it using SQL in Grails, however I wonder how it can be done using hql.
The sql code is as following.
Select survey.*,ao.* from survey sr left outer join order ao on ao.survey_id=sr.id
Models are as following
class Order{
Survey survey
}
class Survey {
}
Try this:
SELECT sr, (SELECT ao FROM namespace.Order ao WHERE ao.survey = sr.id)
FROM namespace.Survey sr
You list all Survey objects and if exists an associated Order you'll get by subquery
Pay attention: I've add namespace term, you'll change with your namespace class
In order to do joins in HQL, you have to extend your domain model. Add a back-ref to your Survey class:
class Survey {
static belongsTo = [ order:Order ]
}
so, you can resolve the Order instance from it:
Survey s = Survey.get someId
s.order
or
def orders = Survey.executeQuery 'select order from Survey where order.id = 111'
I have an Domain Class called Contact with multiple hasMany Relationships and another Domain Class Employee which is part of Concat.
Contact has an table contact and Employee should be mapped on a View which looks like this:
SELECT * FROM contact where employee=1
Employee should have the same columns and Relationship than Contact, how do I write the Domain Classes?
Can I use inheritance?
EDIT
Now I have used inheritance like this:
class Employee extends Contact { }
class Contact{
static mapping = {
tablePerHierarchy(false)
}
}
That works so far, but now I want to add some Relationships to Employee, like this:
class Employee extends Contact {
static belongsTo = [CostCenter ]
static hasMany = [costCenter: CostCenter]
static mapping = {
costCenter joinTable: 'employee_cost_center', column: 'employee_id'
}
}
class CostCenter {
static hasMany = [employees:Employee]
static mapping = {
employeesjoinTable: 'employee_cost_center', column: 'cost_center_id'
}
}
now I have the problem that the table 'employee_cost_center' makes an referen to Contact which is good, but also added 'employee_id':
contact_id
employee_id
cost_center_id
So i could add the relationships to Contact but then I have in CostCenter Contact and not Employee.
How can I add Relationships to Employee?
I think you're on track using inheritance. Since Employee is backed by a database view which selects a subset of Contacts, an Employee is a Contact. So you've got a good candidate for inheritance.
Table-per-subclass inheritance
You described the employee view as follows:
SELECT * FROM contact where employee=1
When using table-per-subclass inheritance the table generated for subclasses contain the following columns:
ID (primary key)
Columns for properties added to the subclass (are not in the superclass), excluding properties for associations.
Since Employee does not, and cannot add, additional properties, the view should only return the primary key.
SELECT id FROM contact where employee=1
I have an article that compares table-per-hierarchy to table-per-subclass inheritance and demonstrates what it looks like at the database level.
Join tables
In your domain class examples you described a join table to create the many-to-many relationship between Employee and CostCenter. Join tables should have two, and only two, columns:
The foreign key (the me domain class)
The foreign key of the other domain class.
So your employee_cost_center table should have the columns employee_id and cost_center_id. If you must specify the join table explicitly, use key instead of column.
costCenter joinTable: 'employee_cost_center', key: 'employee_id'
employees joinTable: 'employee_cost_center', key: 'cost_center_id'
belongsTo
You have Employee belong to CostCenter as so:
static belongsTo = [CostCenter ]
Maybe that's a typo, but if you're not defining a back-reference then the belongsTo should be defined as simply the class, like this:
static belongsTo = CostCenter
I've never used belongsTo this way so I don't know what it looks like in the database. But note that if you have a back-reference, defined like this:
static belongsTo = [costCenter: CostCenter]
Then, your employee view must return a cost_center column.
I am trying to execute a query to gather specific data but encountering problems in the query on the on portion of the query. To start off this is my class:
class TimeSlot {
String timeslot_id
String time_chunk_id
String uid
String exam_id
String start_time
String is_special_arrangement
static mapping = {
table 'timeslot'
id name: "timeslot_id", column: "timeslot_id"
version false
}
}
This is the query I'm trying to get working:
TimeSlot.executeQuery("Select t.time_chunk_id, t.uid, t.start_time, t.timeslot_id, t.is_special_arrangement, e.length from TimeSlot t inner join Exams e on t.exam_id = e.exam_id where t.exam_id = ? and t.time_chunk_id = ?", [testArray[i], timeChunkArray[x]])
It's throwing an error on the on portion because it's expecting a clause, but I need the data to specifically pertain to the exam.id comparison of both tables. Is there another way around this or a different way to set up the query so it will work like it does in any SQL editor?
It would be easier if you alter the domain class and add one to many relationship
class TimeSlot {
static hasMany = [examinations:Exams]
Then HQL can be
select ... from TimeSlot t join t.examinations e
Suppose I have a setup like the following:
class User {
static hasMany = [items : Item];
}
class Item {
String name;
}
I'm trying to select all Users that have an Item in that hasMany mapping. I have an id of an Item, and want to find all users that “have” that item.
Is there a HQL query I can run that will do this or better yet, a built in GORM function that handles this query?
Supposing this were straight SQL I would do something like:
SELECT `user_id` FROM `user_item` WHERE `item_id`=[ID]
Looking in H2 I can write the query
SELECT USER_ID FROM USER_ITEM WHERE ITEM_ID=1;
I can expand this SQL to include the entire user object:
SELECT * FROM user, user_item WHERE user_item.item_id=[item id] AND user.id = user_user.user_items_id;
This HQL will work:
Item item = ...
Item.executeQuery(
'from User u where :item in elements(u.items)',
[item: item])
I have a postgresql database that has this column structure:
Author
id
name
Book
id
name
author_id
And Groovy Domain Classes that repressent those tables:
class Author {
static hasMany = [ books : Book ]
Integer id
String name
}
class Book {
static belongsTo = Author
Integer id
Integer project_id
String name
}
My main goal to get a list of books from a author instance.
author = Author.get( 1 ) // gets a author
author.books // must return a list of books.
But this does not work. Is there something glaringly obvious I'm doing wrong?
note I've got lots of Ruby/Rails experience and zull Java/Groovy experience.
Change your Book class to:
class Book {
static belongsTo = [authors: Author]
static mapping = {
authors column: 'author_id'
}
Integer id
Integer project_id
String name
}
If you don't specify the mapping like that, GORM will create, resp., expect, a JOIN table by default.
(BTW, domain classes are automatically provided with a "virtual" id property (of type Long I think, translating to bigint in PostgreSQL). It's not necessary to specify it manually, but it also won't harm.)
EDIT: Updated as per the questioners comments:
If a book can really have just one author, you'd state in the Book class:
Author author
static belongsTo = [author: Author]
static mapping = { author column: 'author_id' }
The GORM documentation on one-to-many relations can be found here.