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!
Related
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"]
}
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'm using JSON type in postgreSQL. I am able to solve the could not identify an equality operator for type json problem on my local machine by adding:
execute <<-SPROC
-- This creates a function named hashjson that transforms the
-- json to texts and generates a hash
CREATE OR REPLACE FUNCTION hashjson(
json
) RETURNS INTEGER LANGUAGE SQL STRICT IMMUTABLE AS $$
SELECT hashtext($1::text);
$$;
-- This creates a function named json_eq that checks equality (as text)
CREATE OR REPLACE FUNCTION json_eq(
json,
json
) RETURNS BOOLEAN LANGUAGE SQL STRICT IMMUTABLE AS $$
SELECT bttextcmp($1::text, $2::text) = 0;
$$;
-- This creates an operator from the equality function
CREATE OPERATOR = (
LEFTARG = json,
RIGHTARG = json,
PROCEDURE = json_eq
);
-- Finaly, this defines a new default JSON operator family with the
-- operators and functions we just defined.
CREATE OPERATOR CLASS json_ops
DEFAULT FOR TYPE json USING hash AS
OPERATOR 1 =,
FUNCTION 1 hashjson(json);
SPROC
However, I do not have the superuser privilege in Heroku. How should I solve the problem?
UPDATE
I am using JSON to store a nested hash, the record is like this:
Company has column properties. properties can be:
{websites:[{url:1,images:[1,2,3],description:1},{url:2,images:[1,2,3],description:2}], wikipedia:{url:1, description:2},facebook:{id:1}}
UPDATE 2
The error message:
PG::UndefinedFunction: ERROR: could not identify an equality operator for type json
LINE 1: SELECT DISTINCT "companies".* FROM "companies" INNER JOIN "reviews...
the error indicator arrow is on SELECT DISTINCT .
the sql is made by the this part in the view:
#review.companies
In model:
class Company < ActiveRecord::Base
store_accessor :properties, [:websites, :fb, :twitter, :linkedin,:country, :city, :street, :postcode]
In migration:
class AddPropertiesToCompany < ActiveRecord::Migration
def change
add_column :companies, :properties, :json
end
end
Thanks for help again.
One solution is to use hstore instead of json field type. The problem with this is casting your existing json to hstore.
Another solution is to use GROUP BY, instead of SELECT DISTINCT, in your queries.
But there are some cases where it would be easier to just change the field type to hstore, for example when using active admin.
I had a HABTM association in one of my models, and active admin would try to query:
db_dev=# SELECT DISTINCT "api_v1_test".* FROM "api_v1_test" INNER JOIN "api_v1_test_users" ON "api_v1_test"."id" = "api_v1_test_users"."test_id" WHERE "api_v1_test_users"."user_id" = 200;
ERROR: could not identify an equality operator for type json
LINE 1: SELECT DISTINCT "api_v1_test".* FROM "api_v1_test" INNER JOI...
Without wanting to spend much time fixing this and figuring out how to rewrite these queries I just converted the field to a hstore and everything is now working as it should.
Also, can you not enter a psql console from heroku to create your functions? or create a new migration for them?
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
I'm new to Groovy and HQL querying but I can't find a solution to this anywhere so it's driving me nuts.
I have two Domain classes which have a one to many relationship defined (a user can have many companies) and I effectively need to do (what would traditionally be called) 'a table join' but clearly with objects.
The classes go like this:
class User {
transient springSecurityService
static hasMany = [company: Company]
String username
String password
boolean enabled
boolean accountExpired
boolean accountLocked
boolean passwordExpired
...
...
...
}
... and the company class
class Company {
static scaffolding = true
String name
String address1
String address2
String address3
String address4
String postCode
String telephone
String mobile // mobile number to receive appointment text messages to
String email // email address to receive appointment emails to
static hasMany = [staff: Staff]
static belongsTo = [user: User]
...
...
...
}
Gorm has created an user_id field within the company table but any attempt to use this in a query returns an error.
So how would I do something like:
select * from user u, company c, where u.id = c.user_id;
What is the best way to do this?
You can effectively use join on the association something like:
HQL
select * from User as u inner join fetch u.company as companies where u.id = ?
Note that using fetch in the query would eagerly fetch the associated collections of companies for a user
findAll()
User.findAll("from User as u inner join fetch u.company as companies where u.id = ?", [1])
Benefit of using findAll instead of HQL is that you can easily implement pagination something like:
User.findAll("from User as u inner join fetch u.company as companies where u.accountExpired = true", [max: 10, offset: 5])
To get a concrete implementation and really understand things in details I would insist to have a look at findAll and HQL associations.