How to map a joinTable with a String foreign key - grails

Having problems setting up a JoinTable in Grails 3.
I have two domain classes (A and B) with a many-to-many relationship to each other. In Grails 3 I have defined the domains with a JoinTable mapping. In the database (MySql v5) I have three tables, A, B, and the join table A_B. The B table uses a "varchar" as the primary key sqlType. Table A uses "int" as the primary key sqlType.
I added an A and B to my database along with an entry in a join table to link the two together.
In my test code, when I try to load the instance of A, A.get(id), I get an error indicating the type of the ForeignKey in the JoinTable is unknown.
Domain A:
static hasMany = [bs: B]
static mapping = {
table "A"
id column: 'id', sqlType: 'int'
bs joinTable: [name: "A_B", key: "a_id"]
}
Domain B:
static hasMany = [as: A]
static mapping = {
table "B"
id column: 'id', sqlType: 'varchar'
as joinTable: [name: "A_B", key: "b_id"]
}
So it seems the "varchar" in B or the foreignKey to B in the join table is being interpreted as a Long.
I was able to get around the problem by adding a third domain for the JoinTable, defining the columns.
Domain AB
Long aId
String bId
static mapping = {
table "A_B"
id composite: ['aId', 'bId']
aId column: 'a_id', sqlType: 'int'
bId column: "b_id", sqlType: 'varchar'
}
Seems like I should be able to set up a JoinTable in Grails 3 without having to define the JoinTable as a domain. Does anyone know how to do this?

OK, I solved the issue. It was a oversight on my part.
All it took was to define the 'id' type in domain B, e.g.,
Domain B:
String id // <= Declare the id.
static hasMany = [as: A]
static mapping = {
table "B"
id column: 'id', sqlType: 'varchar'
as joinTable: [name: "A_B", key: "b_id"]
}

Related

Column 'id' in where clause is ambiguous grails?

I have a RaceRegistration domain that extends Registration
class RaceRegistration extends Registration{
The Registration class has mapping tableperhierarchy set to false so we have two different tables registration and race_registration in the db.
abstract class Registration extends BaseEntity implements Serializable{
static mapping = {
tablePerHierarchy false
This line is throwing
RaceRegistration.executeUpdate('update RaceRegistration r set r.raceParticipant.bibNumber = null where r.id in (:ids)', [ ids: ids])
the following exception
ERROR util.JDBCExceptionReporter: Column 'id' in where clause is ambiguous
ERROR errors.GrailsExceptionResolver: MySQLIntegrityConstraintViolationException occurred when processing request: [GET] /roadrace/bibs/reassignBibNumbers/976945 - parameters:
sort: asc
Column 'id' in where clause is ambiguous. Stacktrace follows:
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Column 'id' in where clause is ambiguous
at com.mysql.jdbc.Util.handleNewInstance(Util.java:411)
at com.mysql.jdbc.Util.getInstance(Util.java:386)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1039)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4098)
looks like since there are two different tables when i do where r.id it is confused which table it should look registration or race_registration.
Is there a way to disambiguate this in the hql query?
i appreciate any insights.
Thanks!

GORM Mapping View

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.

Foreign Key references primary key in the same table grails domain class

I have a table called person with primary key as id and in the same table I have a foreign key as master_id that references id (primry key) in the same table person. How do I create my domain class in grails for person. ?
Table Person
Integer person_id PK auto_increment
String name
String address
String city
Integer FK master_id references Person(person_id)
Just create a field of the appropriate type with a name of master:
class Person {
Person master
}

ID lookup field in GORM in grails

I am new to Grails and GORM and I am trying to One to Many relationship but not with default id field. Here is my scenario:
Table structure in the database:
USERPROFILE
iduserprofile
username
ROLE
idrole
rolename
USER_ROLE
iduserprofile
idrole
Domains:
class Userprofile {
long iduserprofile
String username
static mapping = {
datasource 'ALL'
id name: 'iduserprofile'
version false
}
class Role {
long idrole;
String rolename;
static mapping = {
datasource 'ALL'
id name: 'idrole'
version false
}
}
class UserRole {
Userprofile user
Role role
static mapping = {
datasource 'ALL'
version false
}
}
When I try to get the user or role object from UserRole domain, it is always looking for user_id or role_id in the USER_ROLE table.
Why is it not looking for iduserprofile or idrole? How can i change the code to look for isuserprofile or idrole?
Thanks
GORM by convention will use/generate id as identifier for your domains. If you have legacy tables or just a desire to break convention, you'll need to specify your custom column names. For example for Role mapping, add the following:
static mapping = {
datasource 'ALL'
id name: 'idrole', column: 'idrole'
version false
}
It seems to me that the easiest thing to do would be to copy your database and then change the names of the id fields if you have legacy tables. If not then just make life simple by conforming to convention.

Using hasMany in grails and postgresql

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.

Resources