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) {
...
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.
Is there a way to create an association to an arbitrary domain object in grails?
Something like
class ThingHolder {
DomainObject thing;
}
and then
Book b=new Book(title: "Grails 101").save()
Author a=new Author(name: "Abe").save()
ThingHolder t1=new ThingHolder(thing:b).save()
ThingHolder t2=new ThingHolder(thing: a).save()
So that
ThingHolder.get(t1.id).thing // will be a Book
and
ThingHolder.get(t2.id).thing // will be an Author.
I'm still looking for a grailsier way to do this, but this seems to get the job done.
class ThingHolder {
static constraints = {
thing bindable:true // required so 'thing' is bindable in default map constructor.
}
def grailsApplication;
Object thing;
String thingType;
String thingId;
void setThing(Object thing) { //TODO: change Object to an interface
this.thing=thing;
this.thingType=thing.getClass().name
this.thingId=thing.id; //TODO: Grailsy way to get the id
}
def afterLoad() {
def clazz=grailsApplication.getDomainClass(thingType).clazz
thing=clazz.get(thingId);
}
}
Assuming you have a Book and Author (that do not override the ID attribute for the domain object).
def thing1=new Author(name : "author").save(failOnError:true);
def thing2=new Book(title: "Some book").save(failOnError:true);
new ThingHolder(thing:thing1).save(failOnError:true)
new ThingHolder(thing:thing2).save(failOnError:true)
ThingHolder.list()*.thing.each { println it.thing }
I found some extremely useful tips in these two answers.
How to make binding work in default constructor with transient values.
How to generate a domain object by string representation of class name
UPDATE (based on comment)
Since you don't want to (or can't) extend another class in your domain model, this won't be possible using GORM.
ORIGINAL Answer
Yes, you can do this. It's called inheritance. In your case you would have a Thing which is the super class of both Author and Book.
Your domain model might look like this:
class Thing {
// anything that is common among things should be here
}
class Author extends Thing {
// anything that is specific about an author should be here
}
class Book extends Thing {
// anything that is specific about a book should be here
}
class ThingHolder {
Thing thing
}
Since both Author and Book extend Thing they are considered to be a Thing as well.
However, doing this without understanding inheritance and how Grails/GORM models the data in your database is short sighted. You should research those topics fully to make sure this is really what you want.
I have a filter, for example lets assume the name John Doe is who a user is searching for.
I have the following domain object structure: Company--->Employee--->Name. Where employee is an attribute of company, and name is an attribute of employee. Now, the filter is for the name attribute, but I need to keep a reference to the Company. So for example I did:
companyList.events.each {
if(it.employee!=null){
if(it.employee.name.toString().toLowerCase().contains(filter)){
filterSet.add(it)
}
}
Unfortunately, this operation is very slow for 1500 entries. However if I do something like,
def searchResults = Company.findAll{
employee.name == filter
}
It is very fast, but I need the filter to get matched with partial names (i.e. saying Joh would still match John Doe. I know there is an operation called like but I have been unsuccessful using it.
Any help would be really appreciated.
I suggest you look at using criteria. So in this case you could do this:
def filter = 'joh'
def searchResults = Company.createCriteria().list() {
employee {
ilike('name', "%${filter}%")
}
}
Try this:
Company.findAll ("from Company c where c.employee.name like '%'| |:filterName| |'%'", [filterName: yourFilterName])
This query has to be fast.
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 }
I'm saving contacts (email, mobile phone, ICQ, AIM etc.) for people like this:
class Person {
static hasMany = {
contacts: Contact
}
}
class Contact {
String code
ContactType type
}
class ContactType {
String name
}
In my view, I've written some Templates for displaying each contact with a select-box for the contact-type and a textfield for the code, spiced up with some JavaScript for adding and deleting.
My question is: Is there an easy and elegant way to update the data similar to personInstance.properties = params or do I have to read out all the fields, deleting removed, updating changed and adding new ones?
I was looking into this some time ago but never got to refactor our code which handles parameters the old-fashioned way.
According to http://www.grails.org/Controllers+-+Data+Binding you can do something like this
def person = new Person(params['person'])
def contact = new Contact(params['contact'])
def conctactType = new ContactType(params['contactType'])
as long as request params are properly namespaced
person.contact.code
person.contact.type.name
You would still have to find out how to handle one to many. Maybe someone who knows can chip in.
Edit:
Came across this doc which describes how to handle one-to-many. It doesn't appear on the main grails site:
http://svn.codehaus.org/grails/tags/GRAILS_DOCS_1_1/src/guide/6.1.6%20Data%20Binding.gdoc