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 }
Related
I am trying to query a domain that looks like this:
class MyDomain {
String something
String somethingElse
Set someStrings
static hasMany = [someStrings: String]
static mapping = {
//... etc.
someStrings: cascade: 'all'
//... etc.
}
}
The domain is in a dependency I didn't write and can't modify.
I would like to find all MyDomains where the Set someStrings contains, say, 'xyz'.
Please show me how, dynamically, with a criteria, or whatever you consider the best practice, I can do this in Grails. My project and the dependency are using Grails 2.44.
In my opinion, using a Collection as a property in a grails Domain is already an anti-pattern, so asking for a "best practice" on top of that is kind of ironic.
FWIW, here's my attempt.
Grails builds a table for your Set of strings, so you can use a classic SQL query, and bind the results to the domain class, like this:
import myapp.MyDomain
class MyDomainService {
List<MyDomain> findByKeyword(String keyword) {
MyDomain.withSession {session ->
def query = session.createSQLQuery("select distinct main.* from MY_DOMAIN as main inner join MY_DOMAIN_SOME_STRINGS as detail on main.id=detail.MY_DOMAIN_ID where detail.SOME_STRINGS_STRING = :keyword")
query.addEntity(MyDomain.class)
query.setString("keyword", keyword)
query.list()
}
}
}
I could not test the code, so there may be typos. I believe that my table and column names match what grails would generate for your example. In any case the principle of binding a domain class to a resultset works in my code.
UPDATE:
Not sure if it will work, but you could try this:
MyDomain.findAll {
someStrings.contains "xyz"
}
It is theoretically possible within the DSL of where queries, but I haven't tried it. I'd be impressed if they thought about this.
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
}
My grails app has the following classes
class Person {
Address address
// other attributes
}
class Address {
String street
City city
// more attributes
}
I would like to query the first 5 people alphabetically by street name. Currently I do something like
def criteria = Person.createCriteria();
def people = criteria.list(max:5) {
address {
order("street","asc")
}
}
This works. I'm just wondering if there's a shorter way to do this (possibly without the criteria builder).
Actually I think this is the clearest and most efficient way of doing it. You could try things like executeQuery, but to be honest, I'm not sure if that's any less verbose. If you're just trying to shorten the code, you could simplify the first two lines:
def people = Person.createCriteria().list(max:5) {
...
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()
My problem should be obvious, but I just don't see the light right now :-(
I have two domainclasses like this:
class Parent {
String name
static hasMany = [children: Child]
}
class Child {
String name
}
Now I should be able to find the Parent of a child by using the dynamic finder of the Parent like:
Parent.findByChildren([someChild] as Set)
But I get a hibernate error stating that I've got a grammar error in my hibernate SQL:
Caused by: java.sql.SQLException: No value specified for parameter 1
And for the reference: someChild IS a concrete instance. And I would like to avoid Child to have an explicit parent in the definition.
How then can I go from the Child to the Parent?
Best Regards,
Christian Sonne Jensen
Just to end this question, I wanted to report a solution to my "problem". I'm using a namedQuery in the Parent entity (Customer or Producer) like this:
Class Customer {
static hasMany = [channels: Channel]
static namedQueries = {
findByChannel {
channelId ->
channels {
eq 'id', channelId
}
}
}
}
Then I find the Customer like this:
def customers = Customer.findByChannel(channel.id).list()
In this way the Channel are relieved of the burden of knowing anything about who references it, and I don't have to do any artificial relationship tables.
I still think that it must be some kind of mistake that I cannot use one of the dynamic finders:
Customer.findByChannels([channel] as Set)
Maybe the dynamic finders doesn't take one-to-many relationsships into account, and only works for simple attributes??? (I'm using Grails 1.3.1)
Thanks for your replies though!
Christian Sonne Jensen
If you don't want the parent foreign key on the child, you'll have to create a join table for the parent that serves as a surrogate for the child:
class ParentalRelationship {
static belongsTo = [parent: Parent, child: Child]
}
You could then have helper methods on the parent to query for children through the ParentalRelationship object.
With your real implementation of Customers, Channels, and Producers, chances are that you'd want a many-to-many relationship anyways as a channel wouldn't belong to a single customer (or a single producer).
Maybe a better way is to write in the chield the belongsTo something like this:
static belongsTo = [parent: Parent]
And then you can use:
Chield c = ...
Parent parent = c.parent
I would invert it:
class Parent {
String name
static Set<Child> getChildren() {
Child.findAllByParent(this) as Set
}
}
class Child {
String name
Parent parent
}
This uses the same database structure (the child table has a foreign key to parent) but makes it easy to go from one side to the other without being explicitly bidirectional.
One thing does change. Instead of this:
def parent = ...
parent.addToChildren(new Child(...))
parent.save()
you do this:
def parent = ...
def child = new Child(parent: parent, ...).save()
This is more performant because you don't need to load the entire collection just to persist a new child.