How to use gorm cascade update with Grails? - grails

Relationship between my domains :
class Cartridge
{ ...
static hasMany = [cartridgeLanes: CartridgeLane]
static belongsTo = [request:Request]
}
class CartridgeLane
{...
CartridgeLaneSampleAttributes cartridgeLaneSampleAttributes
static belongsTo = [cartridge:Cartridge]
}
class CartridgeLaneSampleAttributes
{...
static belongsTo = CartridgeLane
}
Code for cascade update :
def sampleAttributes = new CartridgeLaneSampleAttributes()
sampleAttributes.sampleId = sample.get("ID")
...
def cartridgeLane = new CartridgeLane()
cartridgeLane.laneId = lane.get("ID") as Integer
...
cartridgeLane.cartridgeLaneSampleAttributes = sampleAttributes
def cartridge = Cartridge.findByCartridgeID(cartridgeId)
cartridge.addToCartridgeLanes(cartridgeLane)
cartridge.save()
First, I'm linking sampleAttributes with cartridgeLane, then I'm finding the cartridge I want to update (linking to cartridgeLane), and finally I'm saving.
This code only INSERT data (eg : add sampleAttributes and cartridgeLane data to cartridge).
My problem is I'm looking for an UPDATE (not an INSERT).
How can I manage cascading update ?
How gorm differentiate an update from an insert ?
Is there a more efficient way for cascading update ?

Depending on how you're calling your update method/closure you may be able to leverage Grails data binding.
As an aside, your domain model may be obfuscating the logic in your application. Hard to see without more detail, but it looks like you're trying to have dynamically bound attributes to a domain class using a Map or something. This type of manipulation will require you to write a lot of the logic yourself, and complicate your model. You may want to reconsider the design.

This cascading update works :
def cartridge = Cartridge.findByCartridgeID(cartridgeId).id as Long
def cartridgeLane = CartridgeLane.findCartridgeLanesByCartridge(cartridge).findByLaneId(laneId)
// Update cartridgeLane domain
cartridgeLane.laneId = lane.get("ID") as Integer
...
// update cartridgeLaneSampleAttributes domain
cartridgeLane.cartridgeLaneSampleAttributes.sampleId = sample.get("ID")
...
cartridgeLane.save()

Related

Errors trying to search a many to many relationship in grails

I'm having trouble contructing a query within an many to many relationship... I have these domain classes:
class Event {
Appuser creator
static belongsTo = Appuser
static hasMany = [guests: Appuser]
and
class Appuser {
static hasMany = [friends: Appuser, events: Event]
So the idea is a user can have friends, and they can set up and own multiple events, and they can also be guests of other user's events.
My issue is constructing a query to get the list of guests for a particular event...
I've tried in my controller:
def guests = Appuser.findAllByEvent(eventInstance)
this gives an error
No property found for name [event] for class
def guests = Appuser.findAllByEvents(eventInstance)
this gives an error
No value specified for parameter 1
Any ideas how to remedy? Thanks.
Appuser.findAllByEvent doesn't make sense because there's no event property in the class. Dynamic finders can only work with persistent properties. findAllByEvents is more likely to work because there is an events property (added by an AST transform because of the hasMany) but you can't query on collections with dynamic finders; you need to use criteria/where/HQL queries for those.
But you don't need a query at all - just use the hasMany property you declared:
Event eventInstance = ...
def guests = eventInstance.guests

Referring to Related Record ID In Controller On Save()

I'm still new to Grails and GORM and I got stumped on this and wasn't able to figure out what I am doing wrong. The intent is to automatically relate the record to the logged in user through the Shiro plugin for Grails.
Class User { static hasMany = [stuff: Stuff] }
Class Stuff { static belongsTo = [user:User] }
Class StuffController {
def create = {
params.put('user', User.createCriteria().get{eq('username',SecurityUtils.subject.principal)}.id)
def stuffInstance = new Stuff(params)
stuffInstance.save()
}
}
I saw in the generate-views version of the create scaffold that the relevant field was referred to as name="user.id", but neither it nor variants (such as user_id) seems to work. The query to the Users domain returns the record id necessary, and params.put in this context seems to correctly append the params object with the new value when I render to a test page (so I'm guessing it's not immutable), but this is what I get from the save():
Property [user] of class [class org.stuffing.Stuff] cannot be null
I've even tried flipping it around and going the other way, with the same result:
User.createCriteria().get{eq('username',SecurityUtils.subject.principal)}
.addToStuff(new Stuff(params))`
.save()
Anyone able to enlighten me on what I'm missing here?
Thanks!
EDIT:
Apparently I was being braindead; I was overriding the "create" method, but the default action is "save" in the _form.gsp template, so it wasn't executing that branch.
On the plus side, I did learn about dynamic finders via Burt below, so it wasn't a total wash.
Thanks for your time, guys!
Your code can be a lot cleaner - there's no reason to use createCriteria here. If you're searching by username, use a dynamic finder:
def stuffInstance = new Stuff(params)
def user = User.findByUsername(SecurityUtils.subject.principal)
stuffInstance.user = user
if (!stuffInstance.save()) {
// inspect stuffInstance.errors
}

How can I declare inList constraints from a controller in Grails?

Can anyone show me how to declare an inList constraint within a Grails controller?
Let’s say I have this class:
class A {
List hello
}
How can I add the inList constraint for the hello List from within the controller?
Define a constraint in which a List property has values validated against a list of lists? Sounds weird. But you can do it. With this class:
class A {
List hello
static constraint = {
hello inList:[['abc','def','ghi'],[1,2,3],['a','b']]
}
}
you can do this in your controller:
def instance1 = new A(hello:['abc','def','ghi']).save() //valid
def instance2 = new A(hello:[1,2,3]).save() //valid
def instance3 = new A(hello:['a','b']).save() //valid
def instance4 = new A(hello:['a','b','c']).save() //invalid
def instance5 = new A(hello:[1,2]).save() //invalid
If A is a domain class whose instances are persisted in a traditional database, however, the hello property would be dropped, so you’d need to define it using
static hasMany = [hello: SomeClass]
instead.
You can write a custom validator to your fields that check if data are in List. You will have to implement the in list checking manually.
You can find here the official documentation. There are some stackoverflow entries that can help you like
Grails: Custom validator based on a previous value of the field

How to delete an entry from joined table of many-to-many relationship in grails

I have two domain objects
Class Attachment{
static hasMany = [mailDrafts: MailDraft];
}
Class MailDraft{
static hasMany = [attachments: Attachment]
static belongsTo = Attachment
}
It has created the three tables
1)attachment
2)mail_draft
3)attachment_mail_drafts
attachment_mail_drafts: id, mail_draft_id
Now, I wnat to write a a HQL query to delete an entry from the table 'attachment_mail_drafts' where 'attachment_id' is 4, So what is the query.
You can't do this with HQL, you can read more why here.
Instead you would do the following:
def a = Attachment.get(4)
a.mailDrafts.clear()
a.save()
It seems that in HQL you can only remove objects, removing associations is not possible. You could use raw SQL or use GORM method removeFrom:
def attachment = Attachment.get(1)
def mailDraft = attachment.mailDrafts.find { it.id = 4 }
attachment.removeFromMailDrafts(mailDraft).save(flush: true)
You could implement the m:n collections avoiding the hasMany/belongsTo technique using the approach explained by Mr Burt Beckwith, this improves the performance and can help you to safely delete the 'attachment_mail_drafts' entity that you need.

Grails get any of the children in a hasMany

I have a domain class which has many of another domain class. I want any one of the children and don't care which. Example
class MyDomainClass {
static hasMany = [thingies:OtherDomainClass]
}
I can do this the stupid way like:
def findOne
myInstance.thingies.each{
findOne=it
}
But is there a better way like:
def findOne = myInstance.thingies.grabTheMostConvenientOne()
thingies is a Collection, so you have everything from Collection at your disposal.
A simple way you might do this is:
def one = myInstance.thingies.asList().first()
However, you probably want to make sure the collection actually has some elements first. The documentation doesn't explicitly say that first() throws an IndexOutOfBoundsException if the list is empty, but I have a feeling it still might. If that's the case, you probably want:
def one = myInstance.thingies.size() > 0 ? myInstance.thingies.asList().first() : null
Or, if you want to be super-concise at the expense of some readability, you can use this approach (courtesy John Wagenleitner):
def one = myInstance.thingies?.find { true }

Resources