I'm just trying to do pagination but until now I couldn't make it. I have 2 domain classes and one to many relationship.
class User {
static hasMany = [contacts:Contact]
}
class Contact {
static belongsTo = [ user : User ]
}
I have 20 Contacts.
When I tried to make a query like this :
def maxResult = 20
def startIndex = 0
def contacts = Contact.findAllByUser(user, [max:maxResult, offset:startIndex])
it is not working. Query is working but pagination with gorm is not working. Result is just 1 contact object.
when I tried;
def startIndex = 0
def contacts = Contact.findAllByUser(user, [offset:startIndex])
Result is 20 contact object but when i tried it with different startIndex value, it is not working also. for startIndex = 5, result is also 20 ontact object.
Is there anybody have any idea about this. Maybe i am doing something wrong, maybe it is gorm's problem. I havent found the answer. Thanks for your answers.
I haven't tried the DynamicFinder to do this thing yet, but as I view the document, your syntax seems to be right. As an alternative, I use createCriteria to solve the paging problem.
def queryResult = Contact.createCriteria().list(max: max, offset: offset) {
and {
/// FILTER ///
user {
eq("id", userInstance.id)
}
}
}
Related
Can anyone please help me.I have two domains.
Class Parent{
static hasMany = [child: Child];
}
Class Child{
}
In database there are 20 records.I want to get 10 records only without refreshing the page.So i used remote pagination like.
gsp code is
<util:remotePaginate controller="Parent" action="show"
total="${parentList.size()}"
update="updatedListId" max="10" pageSizes="[10, 20, 50,100]"/>
In Controller i wrote like.
def parent =Parent.get(1);
def parentList = parent.getChild();
I tried this one but its is not working.
def childs = Child.findAllByParent(parent, [max: 10])
It is giving all records but i need to here get only 10 records. I set params max value and pass it as argument but its not working.
please help me.
thanks
You can get the childs in a join via HQL:
Child.executeQuery("select c from Parent p join p.childs c where p=:p", [p:p, max:10])
Have you tried where query?
// Parent.groovy
class Parent{
static hasMany = [ children: Child ]
}
// Where query in controller/service
Parent.where { id == 1L }.children.list(max: 10)
Is there a way that, i can get list of distinct User objects(based on username). And still get result as a List of User Objects rather than, List of username's.
My code is
def criteria = User.createCriteria()
def users = criteria.list() {
projections {
distinct("username")
}
setResultTransformer(CriteriaSpecification.ROOT_ENTITY)
}
return users
Currently am getting List of the usernames, not User.
Ya projection is like filtering and selecting by username you should change it to
def criteria = User.createCriteria()
def users = criteria.listDistinct() {
projections {
groupProperty("username")
}
}
return users
JOB DONE!
One of these should work - I haven't tested any of them, I leave that up to you :)
User.list().unique()
User.list().unique() with the equals() method on the User domain class overridden to compare objects using the username
User.list().unique { it.username } (might need toArray() after list())
def criteria = User.createCriteria()
def users = criteria.list() {
projections {
distinct("username")
}
setResultTransformer(CriteriaSpecification.ROOT_ENTITY)
}
Just replace setResultTransformer(CriteriaSpecification.ROOT_ENTITY) with resultTransformer(ALIAS_TO_ENTITY_MAP). You will get a list of string as a result
otherwise just replace .list with .listDistinct and use do not need distinct("username"), just can be property("username");
Usually people get problems with pagination. not results. If you already had something like:
User.createCriteria().list([max:params.max,offset:params.offset],{
createAlias("others", "others", CriteriaSpecification.LEFT_JOIN);
ilike("others.firstName", "%${query}%");
});
It could result in row duplicates. Because .listDistinct() does not support pagination, just add
resultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
So query will look like this:
User.createCriteria().list([max:params.max,offset:params.offset],{
resultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
createAlias("others", "others", CriteriaSpecification.LEFT_JOIN);
ilike("others.firstName", "%${query}%");
});
Where ever you got a collection (list, array, ...) (I don't know if work with any type of collection, but work in all that i could test). Use unique{ it.property }:
Example:
def users = []
for (def room in rooms) {
users.addAll(room.users)
}
return users.unique{ it.id }
Using where query(Detached criteria):
def userListQuery = User.where{
// Your search criteria
}
def userList = userListQuery.list().unique{ it.username }
it should result one query for distinct results.
This will get you the distinct user object based on userName
def userInstance = User.list().unique{ it.user_name}
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 have a table called employee and child table address.
Now I want to get a list of employees sort by address1 in address table using GORM.
Employee.findAllByName(name, [max: maxRecords, offset: 100,sort: Address.address1, order: desc])
the above statement is not working, any suggestions would be appreciated.
Thanks
Try using a criteria query like so...
def c = Employee.createCriteria()
def results = c.list (max: maxRecords, offset: 100) {
eq("name", name)
address {
order("addres1", "desc")
}
}
This works for me!
Another option is to add a default sort order like so...
class Address{
…
static mapping = {
sort address1:"desc"
}
}
However, I always prefer to do things as an 'as-needed' basis rather than define that sorting be done every time even when it may not be needed. U pick. Enjoy!
I am using Nimble and Shiro for my security frameworks and I've just come accross a GORM bug. Indeed :
User.createCriteria().list {
maxResults 10
}
returns 10 users whereas User.list(max: 10) returns 9 users !
After further investigations, I found out that createCriteria returns twice the same user (admin) because admin has 2 roles!!! (I am not joking).
It appears that any user with more than 1 role will be returned twice in the createCriteria call and User.list will return max-1 instances (i.e 9 users instead of 10 users)
What workaround can I use in order to have 10 unique users returned ?
This is a very annoying because I have no way to use pagination correctly.
My domain classes are:
class UserBase {
String username
static belongsTo = [Role, Group]
static hasMany = [roles: Role, groups: Group]
static fetchMode = [roles: 'eager', groups: 'eager']
static mapping = {
roles cache: true,
cascade: 'none',
cache usage: 'read-write', include: 'all'
}
}
class User extends UserBase {
static mapping = {cache: 'read-write'}
}
class Role {
static hasMany = [users: UserBase, groups: Group]
static belongsTo = [Group]
static mapping = { cache usage: 'read-write', include: 'all'
users cache: true
groups cache: true
}
}
Less concise and clear, but using an HQL query seems a way to solve this problem. As described in the Grails documentation (executeQuery section) the paginate parameters can be added as extra parameters to executeQuery.
User.executeQuery("select distinct user from User user", [max: 2, offset: 2])
this way you can still use criteria and pass in list/pagination paramaters
User.createCriteria().listDistinct {
maxResults(params.max as int)
firstResult(params.offset as int)
order(params.order, "asc")
}
EDIT: Found a way to get both! Totally going to use it now
http://www.intelligrape.com/blog/tag/pagedresultlist/
If you call createCriteria().list() like this
def result=SampleDomain.createCriteria().list(max:params.max, offset:params.offset){
// multiple/complex restrictions
maxResults(params.max)
firstResult(params.offset)
} // Return type is PagedResultList
println result
println result.totalCount
You will have all the information you need in a nice PagedResultList format!
/EDIT
Unfortunately I do not know how to get a combination of full results AND max/offset pagination subset in the same call. (Anyone who can enlighten on that?)
I can, however, speak to one way I've used with success to get pagination working in general in grails.
def numResults = YourDomain.withCriteria() {
like(searchField, searchValue)
order(sort, order)
projections {
rowCount()
}
}
def resultList = YourDomain.withCriteria() {
like(searchField, searchValue)
order(sort, order)
maxResults max as int
firstResult offset as int
}
That's an example of something I'm using to get pagination up and running. As KoK said above, I'm still at a loss for a single atomic statement that gives both results. I realize that my answer is more or less the same as KoK now, sorry, but I think it's worth pointing out that rowCount() in projections is slightly more clear to read, and I don't have comment privileges yet :/
Lastly: This is the holy grail (no pun intended) of grails hibernate criteria usage references; bookmark it ;)
http://www.grails.org/doc/1.3.x/ref/Domain%20Classes/createCriteria.html
Both solutions offered here by Ruben and Aaron still don't "fully" work for pagination
because the returned object (from executeQuery() and listDistinct) is an ArrayList
(with up to max objects in it), and not PagedResultList with the totalCount property
populated as I would expect for "fully" support pagination.
Let's say the example is a little more complicated in that :
a. assume Role has an additional rolename attribute AND
b. we only want to return distinct User objects with Role.rolename containing a string "a"
(keeping in mind that a User might have multiple Roles with rolename containing a string "a")
To get this done with 2 queries I would have to do something like this :
// First get the *unique* ids of Users (as list returns duplicates by
// default) matching the Role.rolename containing a string "a" criteria
def idList = User.createCriteria().list {
roles {
ilike( "rolename", "%a%" )
}
projections {
distinct ( "id" )
}
}
if( idList ){
// Then get the PagedResultList for all of those unique ids
PagedResultList resultList =
User.createCriteria().list( offset:"5", max:"5" ){
or {
idList.each {
idEq( it )
}
}
order ("username", "asc")
}
}
This seems grossly inefficient.
Question : is there a way to accomplish both of the above with one GORM/HQL statement ?
You can use
User.createCriteria().listDistinct {
maxResults 10
}
Thanks for sharing your issue and Kok for answering it. I didn't have a chance to rewrite it to HQL. Here is my solution (workaround): http://ondrej-kvasnovsky.blogspot.com/2012/01/grails-listdistinct-and-pagination.html
Please tell me if that is useful (at least for someone).