I'm new to grails, but have previous experience using .net with c# and linq to query databases.
I'm trying to filter a list of objects by optional items using a multiple selection drop box. So to the controller I will get a list of parameters some of which will be null. So I want to have something akin to
DailyProduction.Where(x => loaction.contains(x.location)).Select().ToList().
However, it doesn't see quite as simple with in groovy and grails.
Here is what I've tried:
def filteredList = DailyProductionReport.createCriteria()
def results = filteredList.list {
if(params.locationSelect != null)
'in'("location", [params.locationSelect.each{ it != null}])
}
But I get a Runtime Exception that says:
Class:
java.lang.ClassCastException
Message:
[Ljava.lang.String; cannot be cast to java.lang.String
I've tried look over different forums with out any luck. I'm almost at my wits end. If any groovy master can shed some light on things for me I'd greatly appreciate it.
Thanks
It looks like your problem might be
[params.locationSelect.each{ it != null }]
each is used for iteration and the resulting expression is just the list being iterated over. Also, the square brackets nest that list in another list. You probably want
'in'('location', params.locationSelect.findAll { it != null })
In this particular case, you can also just use the identity closure since "groovy truth" for objects is the same as testing for null:
'in'('location', params.locationSelect.findAll())
Related
I have the following code
PagedResultList res = myService.getPage(paginateParams, ...)
println res.size() // returns 2
println res.getTotalCount() // returns 1
getPage looks like:
def criteria = MyDomain.createCriteria()
criteria.list(max: paginateParams.max, offset: paginateParams.offset) { // max is 10, offset is 0, sortBy is updatedAt and sortOrder is desc
eq('org', org)
order(paginateParams.sortBy, paginateParams.sortOrder)
}
why do the two method return different values? The documentation doesn't explain the difference, but does mention that getTotalCount is for number of records
currently on grails 2.4.5
edits:
println on res prints out:
res: [
com.<hidden>.MyDomain: 41679f98-a7c5-4193-bba8-601725007c1a,
com.<hidden>.MyDomain: 41679f98-a7c5-4193-bba8-601725007c1a]
Yes, res has a SINGLE object twice - that's the bug I'm trying to fix. How do I know that? I have an primary key on MyDomain's ID, and when I inspect the database, it's also showing one record for this particular org (see my criteria)
edit 2: I found this comment (http://docs.grails.org/2.4.5/ref/Domain%20Classes/createCriteria.html)
listDistinct If subqueries or associations are used, one may end up
with the same row multiple times in the result set. In Hibernate one
would do a "CriteriaSpecification.DISTINCT_ROOT_ENTITY". In Grails one
can do it by just using this method.
Which, if I understand correctly, is their way of saying "list" method doesn't work in this scenario, use listDistinct instead but then they go on to warn:
The listDistinct() method does not work well with the pagination
options maxResult and firstResult. If you need distinct results with
pagination, we currently recommend that you use HQL. You can find out
more information from this blog post.
However, the blog post is a dead link.
Related: GORM createCriteria and list do not return the same results : what can I do?
Not related to actual problem after question edited but this quote seems useful
Generally PagedResultList .size() perform size() on resultList property (in-memory object represent database record), while .getTotalCount() do count query against database. If this two value didn't match your list may contain duplicate.
After viewing related issues (GORM createCriteria and list do not return the same results : what can I do?) I determined that there were several approaches:
Use grails projection groupBy('id') - doesn't work b/c i need the entire object
USe HSQL - Domain.executeQuery - actually this didn't work for my scenario very well because this returns a list, whereas criteria.list returns a PagedResultList from which I previously got totalCount. This solution had me learning HSQL and also made me break up my existing logic into two components - one that returned PagedResultList and one that didn't
Simply keep a set of IDs as I process my PagedResultList and make sure that I didn't have any duplicates.
I ended up going with option 3 because it was quick, didn't require me to learn a new language (HSQL) and I felt that I could easily write the code to do it and I'm not limited by the CPU to do such a unique ID check.
I found a very strange behavior in our grails application today that i want to share with you.
We are using grails 2.3.11 on mysql 5.1.48.
We had a DomainObject.findById( id ) in one of your Controller actions.
We failed to check the id for a null value so DomainObject.findById( null )
would be called when no id is passed as an argument.
Normally DomainObject.findById( null )
will return null but there is a special condition that will yield other results!
If the controller action called before that inserted a new record in the database (lets call it Object B), regardless of the domain object stored, the DomainObject.findById( null ) will find the DomainObject with the same Id the Object B got on insert.
So when the controller action called before saved anything the findById(null) will return a row. And that row will have the same id the last inserted element got.
I am totally aware that using findById(null) is not the desired way to do it but I was quite shocked about the results it yielded. But returning any seemingly "random" result seems very strange to me.
I also want to note that DomainObject.get(null) will not suffer from this problem.
Anybody else witnessed this?
There is an active Jira pointing in this direction: https://jira.grails.org/browse/GRAILS-9628 but its not really describing this issue.
We don't really support passing null as an argument to a dynamic finder like that. Dynamic finders have explicit support for querying by null. Instead of DomainClass.findByName(null) you would call DomainClass.findByNameIsNull(). If you have a reference that may or may not be null, instead of passing that as an argument to a dynamic finder, the code can almost always be made cleaner by writing a criteria query or a "where" query that has a conditional in it.
I hope that helps.
Thx for your information scot.
I have further details. This behaviour is also altered by the underlying database.
While mysql suffers from this, maria-db (a mysql clone) does not!
So what happens is bound to the underlying database system.
That should not happen to an abstraction layer ....
Is there any way to get a PagedResultList in grails without using criteria? I would like to avoid criteria as they are slightly more complex and make unit testing rather annoying. Code Below
def pagedResultList = MyDomainClass.createCriteria().list(max:10, offset:0)
{ order("id", "asc") }
//Below does not return pagedResultList
def aList = MyDomainClass.list(sort:"id", order:"asc", max:10, offset: 0)
PagedResultList is just used to wrap the results of Criteria-based queries (you can see its use in the source here). If you really want to use it, you could always just invoke the constructor directly, since it will handle any list. Of course the totalCount property (which is probably what you are interested in) will then be unset.
If the idea is to get both the paged results list and the total number of results, I'm not aware of any magic that can get both in one query (even the use of PagedResultList in the source linked above issues two queries).
This seems to break in Grails 2.x because there is no costructor that just takes a list. Compare http://grails.org/doc/2.1.0/api/grails/orm/PagedResultList.html and http://docs.huihoo.com/grails/1.3.7/api/grails/orm/PagedResultList.html
I'm attempting to pull up all entities that have a name that doesn't partially match a given string.
MyEntity.findAllByNameNotLike('bad%')
This gives me the following error:
No such property: nameNot for class: MyEntity
Possible solutions: name" type="groovy.lang.MissingPropertyException">
I had a quick look at the criteria style but I can't seem to get that going either,
def results = MyEntity.withCritieria {
not(like('name', 'bad%'))
}
No signature of method: MyEntity.withCritieria() is applicable for argument types: (MyService$_doSomething_closure1)
Ideally I would like to be able to apply this restriction at the finder level as the database contains a large number of entities that I don't want to load up and then exclude for performance reasons.
[grails 1.3.1]
I've worked out how to do this using withCriteria, the not should have been a closure of its own.
def results = MyEntity.withCritieria {
not {
like('name', 'bad%'))
}
}
The problem I initially had using withCriteria was that I was trying to test this as a unit test, which works fine with the dynamic finders, but not with the criteria API (as far as I can tell).
(I'll leave this unanswered for a day to see if anyone has a better solution, otherwise I'll accept my answer)
I'm working on an application at the moment in ASP.NET MVC which has a number of look-up tables, all of the form
LookUp {
Id
Text
}
As you can see, this just maps the Id to a textual value. These are used for things such as Colours. I now have a number of these, currently 6 and probably soon to be more.
I'm trying to put together an API that can be used via AJAX to allow the user to add/list/remove values from these lookup tables, so for example I could have something like:
http://example.com/Attributes/Colours/[List/Add/Delete]
My current problem is that clearly, regardless of which lookup table I'm using, everything else happens exactly the same. So really there should be no repetition of code whatsoever.
I currently have a custom route which points to an 'AttributeController', which figures out the attribute/look-up table in question based upon the URL (ie http://example.com/Attributes/Colours/List would want the 'Colours' table). I pass the attribute (Colours - a string) and the operation (List/Add/Delete), as well as any other parameters required (say "Red" if I want to add red to the list) back to my repository where the actual work is performed.
Things start getting messy here, as at the moment I've resorted to doing a switch/case on the attribute string, which can then grab the Linq-to-Sql entity corresponding to the particular lookup table. I find this pretty dirty though as I find myself having to write the same operations on each of the look-up entities, ugh!
What I'd really like to do is have some sort of mapping, which I could simply pass in the attribute name and get out some form of generic lookup object, which I could perform the desired operations on without having to care about type.
Is there some way to do this to my Linq-To-Sql entities? I've tried making them implement a basic interface (IAttribute), which simply specifies the Id/Text properties, however doing things like this fails:
System.Data.Linq.Table<IAttribute> table = GetAttribute("Colours");
As I cannot convert System.Data.Linq.Table<Colour> to System.Data.Linq.Table<IAttribute>.
Is there a way to make these look-up tables 'generic'?
Apologies that this is a bit of a brain-dump. There's surely imformation missing here, so just let me know if you'd like any further details. Cheers!
You have 2 options.
Use Expression Trees to dynamically create your lambda expression
Use Dynamic LINQ as detailed on Scott Gu's blog
I've looked at both options and have successfully implemented Expression Trees as my preferred approach.
Here's an example function that i created: (NOT TESTED)
private static bool ValueExists<T>(String Value) where T : class
{
ParameterExpression pe = Expression.Parameter(typeof(T), "p");
Expression value = Expression.Equal(Expression.Property(pe, "ColumnName"), Expression.Constant(Value));
Expression<Func<T, bool>> predicate = Expression.Lambda<Func<T, bool>>(value, pe);
return MyDataContext.GetTable<T>().Where(predicate).Count() > 0;
}
Instead of using a switch statement, you can use a lookup dictionary. This is psuedocode-ish, but this is one way to get your table in question. You'll have to manually maintain the dictionary, but it should be much easier than a switch.
It looks like the DataContext.GetTable() method could be the answer to your problem. You can get a table if you know the type of the linq entity that you want to operate upon.
Dictionary<string, Type> lookupDict = new Dictionary<string, Type>
{
"Colour", typeof(MatchingLinqEntity)
...
}
Type entityType = lookupDict[AttributeFromRouteValue];
YourDataContext db = new YourDataContext();
var entityTable = db.GetTable(entityType);
var entity = entityTable.Single(x => x.Id == IdFromRouteValue);
// or whatever operations you need
db.SubmitChanges()
The Suteki Shop project has some very slick work in it. You could look into their implementation of IRepository<T> and IRepositoryResolver for a generic repository pattern. This really works well with an IoC container, but you could create them manually with reflection if the performance is acceptable. I'd use this route if you have or can add an IoC container to the project. You need to make sure your IoC container supports open generics if you go this route, but I'm pretty sure all the major players do.