grails GORM: how to access id of super class - grails

I inherited a Grails 1.3.9 project that I need to maintain.
There is a situation when one of the controllers needs to be extended to log creations of extended appointments.
The appointments are defined like this:
class Appointment implements Serializable{
static mapping = {
table 'appointment'
version false
tablePerHierarchy false
id generator:'sequence', params:[sequence:'seq_te_id']
cache true
columns{
id column:'te_id'
start column: 'te_start'
// Other columns follow
}
}
}
Special appointment:
class SpecialAppointment extends Appointment implements Serializable {
static mapping = {
table 'special_appointment'
cache true
columns{
id column: 'pt_id'
comment column: 'pt_name'
// other columns
}
}
}
History log:
class AppointmentHistory {
static mapping = {
version false
table 'appointment_history'
id generator: 'sequence', params:[sequence:'seq_th_id']
cache true
columns {
id column: 'th_id'
termin column: 'pt_id'
// other columns
}
}
}
In the controller to create SpecialAppointment, which has Appointment as its base class, I need to create and save new instance of AppointmentHistory, which has a relation to Appointment.
def app = new SpecialAppointment()
// set fields here
app.save(flush:true)
// save history log
def history = new AppointmentHistory(appointment: app)
I passed instance of SpecialAppointment when creating history object, but it is wrong, because it uses its ID, instead of ID of Appointment.
Unfortunately I was not able to figure out proper syntax to access members of super class from just saved instance of derived class.
Please advise.

SpecialAppointment being a sublcass of Appointment produces only one object and one row in the table, so they have common ID. Inheritance is not a relation where one sub-object contains the super-object, but a sub-object IS as super-object as well
in other words, it's fine that it uses ID of SpecialAppointment, because SpecialAppointment can also be referenced by Appointment class object

The real problem was that the relations between domain classes were not properly set.
AppointmentHistory needed belongsTo Appointment and Appointment needed hasMany AppointmentHistory. The history item must be added to appointment with app.addHistoryItem(history).
These changes solved the problem.
Thanks everybody for support.

Related

hasMany mapping table not created

I am having a GORM issue.
I try to map one domain Object with another with hasMany.
class PrototypePriceModifierCode {
...
static hasMany = [activitys:Activity]
...
}
Since I don't need a back reference in Class Activity I don't have any reference to PrototypePriceModifierCode.
Having only this creates my mapping table as expected (1).
prototype_price_Modifier_code_id activity_id
In the Activity, I need a reference to a PrototypePriceModifier, which has nothing to do with the above mapping table.
The problem is that the mapping table is not generated anymore as soon as I define
class Activity{
...
PrototypePriceModifierCode prototypePriceModifierCodeAttached
How can I get the mapping table created and having a reference to PrototypePriceModifierCode in my Activity domain class?
Try like this:
class Activity {
static belongsTo = [PrototypePriceModifierCode]
}
This way, there will be a column in the activity table for PrototypePriceModifierCode instead of creating a separate table for hasMany.
When Activity does not have the prototypePriceModifierCodeAttached property, the hasMany in PrototypePriceModifierCode results in a uni-directional one-to-many association. In the database, this is implemented with a mapping table.
However, when Activity has the prototypePriceModifierCodeAttached property the association changes to a bi-directional one-to-many. In the database this means the activity table has a foreign key pointing to it's prototype_price_modifierCode, so the mapping table is not used. You can read more about these differences here.
"prototypePriceModifierCodeAttached" property
If you want a uni-directional one-to-many and the property Activity.prototypePriceModifierCodeAttached, you can create a getter method which looks up the PrototypePriceModifierCode:
class Activity {
PrototypePriceModifierCode getPrototypePriceModifierCodeAttached() {
PrototypePriceModifierCode.where {
activitys.id == this.id
}.get()
}
}
The downside here is that the property is inaccessible to GORM; can't query on it.
"price_modifier_code_id" column
On the other hand, if what you want is a price_modifier_code_id column in the activity table, you can add it as a long:
class Activity {
long prototypePriceModifierCodeAttached
static mapping = {
prototypePriceModifierCodeAttached column: 'price_modifier_code_id'
}
}
This makes it possible to use GORM queries on the property, but only on the PrototypePriceModifiedCode ID, not the domain class instance itself.
A combo
You can combine both approaches, as long as you're willing to do a bit of maintenance:
class Activity {
long priceModifierCodeId // <--- You gotta maintain this property manually.
PrototypePriceModifierCode getPrototypePriceModifierCodeAttached() {
PrototypePriceModifierCode.get(priceModifierCodeId)
}
}
Note: activitys is misspelled. It should be activities.
I ended up using String saving comma separated ids.
String activitys
this.activitys.split(',')each{
p.activitys.add(Activity.get(Long.parseLong(it)))
}
As I don't need referencial integrity here this works fine for me.

Understanding hasMany behavior in grails and how to save a relationship

I'm making a model where a User fills out many questionnaires and the responses get saved to Questionresponse. I'm on grails 2.5.2
Test1
So I have two models
class User {
String username
...
static hasMany = [reponse: QuestionResponse]
}
class QuestionResponse {
String question_1
String question_2
...
}
With the above, a new DB table is created: user_questionresponse with two columns user_questionresponses_id and questionresponse_id. This seems like what I want. A user would have many questionresponses and those relationships would be saved in this table. However, I can't find out how to save data to this table.
For example, if I do:
def user = springSecurityService.currentUser
def questionnaire = new QuestionResponse(question_1: "foo", question_2: "bar")
//How do I link the user to this newly created questionnaire?
user.addToResponse(q).save(flush: true) //DOES NOT WORK.
Test2 (just add belongsTo)
class User {
String username
...
static hasMany = [reponse: QuestionResponse]
}
class QuestionResponse {
String question_1
String question_2
static belongsTo = [user: User]
...
}
If I add belongsTo to QuestionResponse a new column, user_id, gets created in the DB. Now if I run the same code as above, this user_id column has the id populated with that of the current user. However, the relationship table, user_questionresponse is still empty.
I am aware of the approach mentioned by Burt but I assume that should be required only for ManyToMany relationship. If that is required for all relationship, why isn't that the default?
In your first case, you have a OneToMany relationship between User and QuestionResponse with no side being the owner of the relationship. In this case to maintain the relationship between User and QuestionResponse, a third table is required. To persist data you need to do the:
userInstance.addToResponse(new QuestionResponse(question_1: "foo", question_2: "bar")).save(flush: true, failOnError: true)
You are doing user.addToReponse(q) instead it should be user.addToReponse(questionnaire), if it's not a typo and the data is actually not being stored, then check by adding the failOnError parameter to save() method. Sometimes grails save() method fails silently, it should tell you if this is the case.
In second case, you have added the parent to the relationship, so that means you don't need the third table to maintain the relationship. Grails will not create and populate the third table in this case.
The second approach (adding belongsTo in QuestionResponse) seems the right thing to do in your case, since QuestionResponse objects cannot exists without a user and cannot belong to different users.
In that case there's no need to use a third table.
When you run the app for the first time, grails created the relation table (because there was no belongsTo). When you run the app again with belongsTo grails adds the user_id field but DOES NOT DROP the relation table. That's why the table is there and is empty: it's not needed, but grails database auto-update feature only adds things, it does not remove anything.
The same applies to fields: if you remove a field from an entity you have to manually remove it from the database.

GORM and Composite Keys in associations

I have legacy database and some tables have composite ids
class Client {
String id
static hasMany = [
settings: Setting
]
static mapping = {
id column: 'client_id', generator: 'assigned'
}
}
class Setting {
Client client
String nodeId
String ccyPairPattern
Character qualifier
static mapping = {
id composite: ['client', 'nodeId', 'pattern', 'qualifier']
}
}
I want to delete entry from GORM association:
client.get('1').removeFromSettings(settingToRemove)
// settingToRemove.delete(flush: true)
// delete-orphans does not help
This always raises exception after flush
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) :
This happens because method removeFrom* sets client property to null and generates query to delete with clientId = null as client is part of composite key
What is the best solution in this case. Looks like GORM has poor support for composite keys or my mapping is incorrect.
When you use hasMany without a belongsTo on the many side, in other words a unidirectional association, you get a join table. For example...
class PurchaseOrder {
static hasMany = [items: Item]
}
class Item { }
Would yield three database tables: purchase_order, item, and purchase_order_items. The purchase_order_items table would contain two columns: purchase_order_id and item_id. You can read more about join tables here.
Since you're dealing with a legacy database, I think the best solution is not to use addTo*() and removeFrom*().
Ensure you don't have a join table. If you have a join table, remove the hasMany association.
You'll need to add/remove Setting instances manually.
Example:
def client = Client.get(1)
// Adding a setting
def setting = new Setting(client: client, nodeId: blah...)
setting.save()
// Removing a setting
/*
The prototype is used to search for a domain instance with a composite primary key.
So simply set the composite key properties accordingly.
*/
def prototype = new Setting(client: client, nodeId: blah...)
def setting = Setting.get(prototype)
setting.delete()
Lacking a hasMany association, you won't be able to access a client's settings via the client.settings property. Instead you'd have to query for them like this:
def settings = Setting.findByClient(client)
A consequence of using a legacy database is that if the database doesn't align with that GORM/Hibernate expects it will be limited in what it can do for you.

Grails creating constrain for unique object on multiple attribute of Domain Class

I have a Domain Class as First.
which has attributes named objectA of ClassA, a String name and a Joda DateTime object as date.
There must be a unique object of First for every unique combination of date, objectA and name.
I have given the following definition of teh class and the constraint. This works perfectly fine if I am creating the domain object from grails scaffolding View.I get error if I create a duplicate entry:
1 error prohibited this record from being saved
There were problems with the following fields:
Property [name] of class [class in.test.First] with value ["nameValue"] must be unique
But the same object gets created multiple times if code is executed from a service or controller.(It's very weird.)
class First {
ObjectId id
ClassA objectA
String name
DateTime date
static mapping = {
date index: true
objectA index: true
name index: true
}
static constraints = {
name(unique: ['objectA', 'date'])
}
What is the correct way of defining a Domain class with such properties?
PS : No hibernate plugin is used, using mongoDB as only Database.
plugins {
....
compile ":mongodb:3.0.3"
compile ":spring-security-core:2.0-RC5"
....
}
UPDATE:
Looked this Question
added
static mapping = {
id composite: ['objectA', 'date', 'name']
}
But, this does not seems to work.

Grails many-to-many relationship across the same table

I'm using Grails and I want to have a unidirectional many-to-many relationship.
In my application, an Employee can "bookmark" another Employee in order to quickly access them to leave notes. Employees need not know who has bookmarked them.
In other words, I essentially want to have an employee.bookmarks property that I can use for this.
Thus far, I've found the documentation on many-to-many relationships for Grails ORM, but this seems to be exclusively across two different tables.
Sounds like you just need a regular unidirectional 1-many:
class Employee {
...
static hasMany = [bookmarks: Employee]
}
You can use transient properties and an additional table "Bookmark" to do this task:
class Employee {
String name
static transients = ["bookmarks"]
def getBookmarks() {
Bookmark.findAllByBookmarker(this, [sort: "id", order: "asc"])
}
...
}
class Bookmark implements Serializable {
Employee bookmarker // the employee who bookmark someone
Employee bookmarkee // the employee who is bookmarked
static mapping = {
table "Bookmark"
id composite: ['bookmarker', 'bookmarkee']
bookmarker(column: "BOOKMARKER_ID")
bookmarkee(column: "BOOKMARKEE_ID")
version false
}
static Bookmarker get(long bookmarkerId, long bookmarkeeId) {
find 'from Bookmark where bookmarker.id=:bookmarkerId and bookmarkee.id=:bookmarkeeId',
[bookmarkerId: bookmarkerId, bookmarkeeId: bookmarkeeId]
}
...
}
This method uses table "Bookmark" to store the relations between employees, so it is possible to have 2 people bookmark the same employee. Note that class Bookmark must implements Serializable.

Resources