I have domain classes A and B as follows:
class A {
String prop1
String prop2
B prop3
static embedded = ['prop3']
}
class B {
String prop4
String prop5
}
When I want to query like this:
def q = A.where { prop3.prop4 == 'bla' }
def list = q.list()
I get the following exception:
Cannot get property 'javaClass' on null object. Stacktrace follows:
on the "def q = A.where ..." line.
Any clue what's the problem? I've checked this:
http://grails.1312388.n4.nabble.com/GORM-embedded-object-issue-td1379137.html
but how to "just call them directly" is not quite clear to me. Any other way of querying the embedded objects in GORM?
I finally gave up on the where query and went with the DetachedCriteria approach. Gives me the same flexibility as the where queries, but works with embedded domain objects:
def criteria = new DetachedCriteria(A).build {
eq 'prop1', 'bla2'
}
criteria = criteria.build {
eq 'prop3.prop4', 'bla'
}
def list = criteria.list()
What do you get if you do (assuming B is in src/groovy)
def q = A.where { prop3 == new B(prop4: 'bla') }
def list = q.list()
Embedded components are persisted inside the main domain class (owner) itself. It can be accessed directly using any dynamic finder as you do directly on a domain object.
The above can also be represented in dynamic finders as:
A.findAllByProp3(new B(prop4: 'bla'))
Related
I am creating a basic CRUD application with a Person entity:
class Person {
public int Age;
...
public int getAge() {
return this.Age;
}
public void setAge(int AgeToSet) {
this.Age = AgeToSet;
}
}
I have a controller and I want to retrieve all Persons with an age of 20:
def filter = {
def c = Person.createCriteria();
def persons = c.list{
eqProperty("Age", "20");
}
[persons: persons];
}
But this is not working and is, instead, giving me the error:
ERROR StackTrace - Full Stack Trace:
org.hibernate.QueryException: could not resolve property: Age of: project.Person
at org.hibernate.persister.entity.AbstractPropertyMapping.propertyException(AbstractPropertyMapping.java:62)
What could be the problem?
Three things:
Your Age needs to start with lowercase: age.
Your criteria is wrong, you want to use eq. eqProperty compares two properties, but you only need one and a value.
Your comparision must be with an int, like this: eq("myage", 20).
Since this query is so simple, you may want to just use a DynamicFinder: http://gorm.grails.org/6.0.x/hibernate/manual/index.html#finders
With a Dynamic Finder, you could simplify the query to:
def persons = Person.findAllByAge(20)
Just a suggestion. I use Dynamic Finders as my primary query method. If I need a query that is more complex, I'll resort to a .createCriteria and then a .executeQuery which takes HQL.
I need some help on my API, when I'm on web, the order is saving correct, but when its on API, it goes all wrong:
def test = parseJSON.sort { a, b -> a.ID <=> b.ID } //or dateTime, will print the same
//order when I print each of them
[IDWeb:0, conductivity:0, ReportId:2, dissolvedOxygen:0, levelWater:1, ID:1, ph:0, redoxPotential:0, temperature:0]
[IDWeb:0, conductivity:0, ReportId:2, dissolvedOxygen:0, levelWater:0, ID:2, ph:0, redoxPotential:0, temperature:0]
[IDWeb:0, conductivity:0, ReportId:2, dissolvedOxygen:0, levelWater:0, ID:3, ph:0, redoxPotential:0, temperature:0]
[IDWeb:0, conductivity:0, ReportId:2, dissolvedOxygen:0, levelWater:4, ID:4, ph:0, redoxPotential:0, temperature:0]
test.each{
def sample = new SampleWater()
sample.levelWater = it.levelWater
sample.conductivity = it.conductivity
sample.dissolvedOxygen = it.dissolvedOxygen
sample.redoxPotential = it.redoxPotential
sample.ph = it.ph
sample.temperature = it.temperature
water.addToSamples(sample)
}
return water
My problem is that addTo is not saving in order. How can I solve this?
Make sure you have defined the type of samples as a List in your Water domain class so that we can maintain the insertion order:
class Water {
static hasMany = [samples: Sample]
List<Sample> samples = []
}
class Sample {
def levelWater
}
By default implementation of hasMany is of type Set which does not maintain the insertion order but is responsible for uniqueness.
Since, now you samples will be saved in the same order as they are inserted.
You have to specify with order you want to apply to the list of SampleWater in the "water" domain class.
i.e:
class BlogCategory {
static hasMany = [
entries : BlogEntry
]
static mapping = {
entries: sort:'dateCreated', order:'desc'
}
}
In this example BlogEntry will be ordered respect dateCreated.
When using projection on the properties, the result is returned as the list with the elements in the same sequence as that defined in the projections block. At the same time the property names are missing from the list and that is really disadvantageous to the developer as the result would be passed along and the caller needs to know what value belongs to which property. Is there a way to return a map from the Criteria query with property name as the key to the value?
so, the following code:
def c = Trade.createCriteria()
def remicTrades = c.list {
projections {
property('title', 'title')
property('author.name', 'author')
}
def now = new Date()
between('publishedDate', now-365, now)
}
This returns:
[['book1', 'author1']['book2', 'author2']]
Instead I would like it to return:
[[book:'book1', author:'author1'][book:'book2', author:'author2']]
I know I can arrange this way after getting the result but I earnestly feel that the property alias should have been used by the criteria to return a list of map that mimics the result of the SQL query and not a bland list.
Duplicate: Grails queries with criteria: how to get back a map with column?
And the corresponding answer (and solution): https://stackoverflow.com/a/16409512/1263227
Use resultTransformer.
import org.hibernate.criterion.CriteriaSpecification
Trade.withCriteria {
resultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP)
projections {
property('title', 'title')
property('author.name', 'author')
}
def now = new Date()
between('publishedDate', now-365, now)
}
Agree with your question reasoning, this really should be part of the core GORM solution. That said, here's my workaround;
def props = ['name','phone']
def query = Person.where {}.projections {
props.each{
property(it)
}
}
def people = query.list().collect{ row->
def cols = [:]
row.eachWithIndex{colVal, ind->
cols[props[ind]] = colVal
}
cols
}
println people // shows [['name':'John','phone':'5551212'],['name':'Magdalena','phone':'5552423']]
I wanted to make some translatable content with rest service so i decided to create collection with this structure. But I can't find BSON by value from String Map.
class LocalizableString{
static mapWith = "mongo"
ObjectId id
Map<String, String> values = new HashMap<String, String>();
}
Then i wanted to get like this. But it works like join query.
def list = LocalizableString.createCriteria().list {
values{ like('value',"%${value}%") }
}
Here is similar plain mongo example. But how can i implement it with gorm mongoDB http://www.mongodb.org/display/DOCS/Schema+Design#SchemaDesign-Example
Is there any solution for that ?
class BaseService {
def findByLocalizableString(def domainClass ,def query , def field ,def params = null) {
def q = new BasicDBObject()
def queryList = []
def allowedLanguages = ConfigurationHolder.config.grails.localizableString.allowedLanguages
allowedLanguages.each { locale ->
queryList.add(new BasicDBObject("values.${locale}", new BasicDBObject('$regex', /.*${query}.*/)))
}
q.put('$or',queryList)
def lsc = LocalizableString.collection.find(q)
def list = lsc.hasNext() ? domainClass.createCriteria().list(params) {
or {
while (lsc.hasNext()) {
def n = lsc.next()
eq("${field}",n._id)
}
}
} : null
return list
}
}
I'm not 100% on this, but I'm fairly certain the Mongo GORM plugin does not work with criteria relation traversal, which is what this looks like (despite not really being like that).
From mongoGorm website (http://blog.mongodb.org/post/18510469058/grails-in-the-land-of-mongodb):
Some of the GORM features that are not supported include:
Criteria queries on associations
HQL
Groovy SQL
So you may need to rethink the Map structure you have as a data model here :/ Anyone more experienced can weigh in?
I have the folowing:
class Store{
String name
}
class Shop{
String name
Store store
}
My criteria builder:
def c = Shop.createCriteria()
def results = c.list {
like("name", "Harrods")
like("store.name", "McDonals")
}
I'm sure this is invalid cause i'v tested it. How can i manage to use criteriaBuilder and do this: like("store.name", "McDonals")?
Looking forward to get any help,
John
Since you're querying an association, try:
def results = c.list {
like('name', 'Harrods')
store {
like('name', 'McDonals')
}
}
This will do an conjoined query between name and store.name.
Check out the documentation Looks like you need to use a % for your like clause.