Grails Criteria Projection - No signature of method projections() is applicable for argument types - grails

As per Grails documentation
Grails also lets you write your domain model in Java or reuse an existing one that already has Hibernate mapping files. Simply place the mapping files into grails-app/conf/hibernate and either put the Java files in src/java or the classes in the project's lib directory if the domain model is packaged as a JAR. You still need the hibernate.cfg.xml though!
So This is exactley what i did.
I have used java domain model and hibernate.cfg.xml file for mapping. I also use
{DomainName}Constraints.groovy for adding Grails constraints. I also used to add functions to {DomainName}Constraints. For example, below is the content of my EmployeeConstraints.groovy
Employee.metaClass.static.findByDepartment = {depCode ->
createCriteria().list {
department{
inList ('code', depCode)
}
}
}
Now this works fine. But, when i add projection to it(code below), just to get the employee code.
Employee.metaClass.static.findByDepartment = {depCode ->
createCriteria().list {
projections { property('empCode', 'empCode') }
department { inList ('code', depCode) }
}
}
I get the below error..
" No signature of method: com.package.script142113.projections() is applicable for argument types.. "
Can someone point me to whats wrong with the code?
Thanks!

The property projection is used to return a subset of an object's properties. For example, to return just the foo and bar properties use:
projections {
property('foo')
property('bar')
}
You're getting an error because you've called the property method with 2 arguments instead of one.
By the way, I see another potential with your code. Grails will automatically create a dynamic finder findByDepartment that has the same name as the method your trying to add via the meta-class. I have no idea which one will take precendence, but I would suggest you avoid this potential problem and simplify your code, by adding this query using Grails' named query support, and call it something like getByDepartment so that the name doesn't class with a dynamic finder.

The answer by Dónal should be the correct one, but I found a strange behavior with grails 3.1. I got the same message using this call:
Announcement.createCriteria().list {
projections {
property('id')
property('title')
}
} .collect { [id: it['id'], title: it['title']] } // it['id'] not found
I fixed it by removing projections closure:
Announcement.createCriteria().list {
property('id')
property('title')
} .collect { [id: it['id'], title: it['title']] } // got the it['id']
Hope this help.

Related

Grails GORM find by object property's property

I am looking for an easier grails way(if it exists) to achieve below:
My UserIntegration.groovy domain class:
class UserIntegration {
User user
Integration integration
// rest of code
}
My Integration.groovy domain:
class Integration {
SomeType type
// rest of code
}
My SomeType.groovy domain:
class SomeType {
String name
// rest of code
}
So basically what I need is a way so that I can find a UserIntegration which has Integration with type.name = "someTypeName"
In other words, I am looking for UserIntegration.findByIntegrationTypeName("someTypeName");
Obviously such a dynamic finder does not exist, but is there any easier groovier way to do it? I can currently find out all Integration objects with type = "someTypeName" and then use this integration in findAllByIntegration but looking for an easier solution if it exists, preferably a dynamic finder.
You can also use HQL to do same
def list = UserIntegration.executeQuery(from UserIntegration userInt
inner join fetch userint.integration integration
inner join fetch integration.type sometype
where sometype.name =:name,[name:'someTypeName'] )
UserIntegration.createCriteria().list(max:1){
'integration'{
'type'{
eq('name',"someTypeName")
}
}
}
Hope it works

breeze: creating inheritance in client-side model

I'm having a weird issue with the configureMetadataStore.
My model:
class SourceMaterial {
List<Job> Jobs {get; set;}
}
class Job {
public SourceMaterial SourceMaterial {get; set;}
}
class JobEditing : Job {}
class JobTranslation: Job {}
Module for configuring Job entities:
angular.module('cdt.request.model').factory('jobModel', ['breeze', 'dataService', 'entityService', modelFunc]);
function modelFunc(breeze, dataService, entityService) {
function Ctor() {
}
Ctor.extend = function (modelCtor) {
modelCtor.prototype = new Ctor();
modelCtor.prototype.constructor = modelCtor;
};
Ctor.prototype._configureMetadataStore = _configureMetadataStore;
return Ctor;
// constructor
function jobCtor() {
this.isScreenDeleted = null;
}
function _configureMetadataStore(entityName, metadataStore) {
metadataStore.registerEntityTypeCtor(entityName, jobCtor, jobInitializer);
}
function jobInitializer(job) { /* do stuff here */ }
}
Module for configuring JobEditing entities:
angular.module('cdt.request.model').factory(jobEditingModel, ['jobModel', modelFunc]);
function modelFunc(jobModel) {
function Ctor() {
this.configureMetadataStore = configureMetadataStore;
}
jobModel.extend(Ctor);
return Ctor;
function configureMetadataStore(metadataStore) {
return this._configureMetadataStore('JobEditing', metadataStore)
}
}
Module for configuring JobTranslation entities:
angular.module('cdt.request.model').factory(jobTranslationModel, ['jobModel', modelFunc]);
function modelFunc(jobModel) {
function Ctor() {
this.configureMetadataStore = configureMetadataStore;
}
jobModel.extend(Ctor);
return Ctor;
function configureMetadataStore(metadataStore) {
return this._configureMetadataStore('JobTranslation', metadataStore)
}
}
Then Models are configured like this :
JobEditingModel.configureMetadataStore(dataService.manager.metadataStore);
JobTranslationModel.configureMetadataStore(dataService.manager.metadataStore);
Now when I call createEntity for a JobEditing, the instance is created and at some point, breeze calls setNpValue and adds the newly created Job to the np SourceMaterial.
That's all fine, except that it is added twice !
It happens when rawAccessorFn(newValue); is called. In fact it is called twice.
And if I add a new type of job (hence I register a new type with the metadataStore), then the new Job is added three times to the np.
I can't see what I'm doing wrong. Can anyone help ?
EDIT
I've noticed that if I change:
metadataStore.registerEntityTypeCtor(entityName, jobCtor, jobInitializer);
to
metadataStore.registerEntityTypeCtor(entityName, null, jobInitializer);
Then everything works fine again ! So the problem is registering the same jobCtor function. Should that not be possible ?
Our Bad
Let's start with a Breeze bug, recently discovered, in the Breeze "backingStore" model library adapter.
There's a part of that adapter which is responsible for rewriting data properties of the entity constructor so that they become observable and self-validating and it kicks in when register a type with registerEntityTypeCtor.
It tries to keep track of which properties it has rewritten. The bug is that it records the fact of rewrite on the EntityType rather than on the constructor function. Consequently, every time you registered a new type, it failed to realize that it had already rewritten the properties of the base Job type and re-wrapped the property.
This was happening to you. Every derived type that you registered re-wrapped/re-wrote the properties of the base type (and of its base type, etc).
In your example, a base class Job property would be re-written 3 times and its inner logic executed 3 times if you registered three of its sub-types. And the problem disappeared when you stopped registering constructors of sub-types.
We're working on a revised Breeze "backingStore" model library adapter that won't have this problem and, coincidentally, will behave better in test scenarios (that's how we found the bug in the first place).
Your Bad?
Wow that's some hairy code you've got there. Why so complicated? In particular, why are you adding a one-time MetadataStore configuration to the prototypes of entity constructor functions?
I must be missing something. The code to register types is usually much smaller and simpler. I get that you want to put each type in its own file and have it self-register. The cost of that (as you've written it) is enormous bulk and complexity. Please reconsider your approach. Take a look at other Breeze samples, Zza-Node-Mongo for example.
Thanks for reporting the issue. Hang in there with us. A fix should be arriving soon ... I hope in the next release.

Change Grails REST format /controller/<id>/<action>

I messed around with this a bit yesterday and failed miserably. I want to convert:
"/$controller/$action?/$id?"
To
#in psudo
"/$controller/$id?/$action?"
#ideal regex
"\/(\w+)(\/\d+)?(\/\w+)?"
The most obvious way failed "/$controller/$action?/$id?"
I can write the regex's to do it, but I am having trouble finding a way to using true regexs (I found RegexUrlMapping but could not find out how to use it), and also can't find documentation on how to assign a group to a variable.
My question is 2 parts:
How to I define a URL Resource with a true regex.
How to I bind a "group" to a variable. In other words if I define a regex, how do I bind it to a variable like $controller, $id, $action
I would also like to be able to support the .json notation /user/id.json
Other things I have tried, which I thought would work:
"/$controller$id?$action?"{
constraints {
controller(matches:/\w+/)
id(matches:/\/\d+/)
action(matches:/\/\w+/)
}
}
also tried:
"/$controller/$id?/$action?"{
constraints {
controller(matches:/\w+/)
id(matches:/\d+/)
action(matches:/\w+/)
}
}
The grails way to deal with this is to set
grails.mime.file.extensions = true
in Config.groovy. This will cause Grails to strip off the file extension before applying the URL mappings, but make it available for use by withFormat
def someAction() {
withFormat {
json {
render ([message:"hello"] as JSON)
}
xml {
render(contentType:'text/xml') {
//...
}
}
}
For this you'd just need a URL mapping of "$controller/$id?/$action?"
I'm not aware of any way to use regular expressions in the way you want in the URL mappings, but you could get a forward mapping working using the fact that you can specify closures for parameter values that get evaluated at runtime with access to the other params:
"$controller/$a?/$b?" {
action = { params.b ?: params.a }
id = { params.b ? params.a : null }
}
which says "if b is set then use that as the action and a as the id, otherwise use a as the action and set id to null". But this wouldn't give you a nice reverse mapping, i.e. createLink(controller:'foo', action:'bar', id:1) wouldn't generate anything sensible, you'd have to use createLink(controller:'foo', params:[a:1, b:'bar'])
Edit
A third possibility you could try is to combine the
"/$controller/$id/$action"{
constraints {
controller(matches:/\w+/)
id(matches:/\d+/)
action(matches:/\w+/)
}
}
mapping with a complementary
"/$controller/$action?"{
constraints {
controller(matches:/\w+/)
action(matches:/(?!\d+$)\w+/)
}
}
using negative lookahead to ensure the two mappings are disjoint.

Grails: No signature of method findAll() is applicable for argument types: String, ArrayList

I'm new to grails and receive the following error:
No signature of method: Something.findAll() is applicable for argument types: (java.lang.String, java.util.ArrayList) values: [from Something AS s WHERE s.some_number LIKE ?, [%asdf%]]"
The error occurs when I run test-app. It occurs in the following place:
SomethingVO[] findBySomeNumber(String searchString) {
searchString = "%"+searchString+"%"
return Something.findAll("from Something AS s WHERE s.some_number LIKE ?",[searchString]).collect {
new SomethingVO(it);
}
}
The class Something is a domain object:
package some.project.domain
class Something{
static belongsTo = [product:Product, productVersion:ProductVersion]
Long id
String name
String someNumber
static constraints = {
product (nullable:true)
productVersion (nullable:true)
}
}
Where is the mistake?
(I use Grails 1.2.4)
findAll is not mocked during unit testing and that's why your code isn't working. You need to manually add a mock for the call before running your test (mockFor could help you with that). This applies if your use HQL or Criterias (which I would recommend over pure HQL).
Alternatively it's possible that you could solve your problems using dynamic finders. Dynamic finders and the other dynamic ORM methods (save, get, count, ..) are in most(?) cases mocked when you call mockDomain(Something) in your unit test. They are also generally easier to use than HQL (imho).
Update:
Thanks to Fletch for pointing out that not all dynamic finders are mocked. An example of a dynamic finder that won't be mocked is this: Something.findAllWhereSomeNumberInList([1, 2, 3]).
The HQL you use in your code could be rewritten like this using dynamic finders:
Something.findBySomeNumberLike(searchString)
Xlson's answer is correct, however there is an alternative "cutting edge" solution you can try, which is currently in testing status. See http://grails.1312388.n4.nabble.com/New-approach-to-mocking-domain-classes-in-Grails-unit-tests-td2529895.html

Grails GORM MissingMethodException with 1:N relationship

I have such domain classes:
class ServicesGroup {
Long id
String name
String description
String toString(){
return name
}
static mapping = {
version false
table 'root.services_groups'
id column:'group_id'
name column:'group_name'
description column:'group_desc'
}
}
and
class Step {
Long id
ServicesGroup service
String stepType
Integer stepFrom
Integer stepTo
static constraints = {
stepType(inList:['operator', 'client'])
}
static mapping = {
version false
table 'bill.steps'
service column:'service_group_id'
}
}
The relationship is - one ServicesGroup entry can have multiple Step instances.
However, when in my controller I try to
Step.findByService(3)
I get:
"org.codehaus.groovy.runtime.InvokerInvocationException: groovy.lang.MissingMethodException: No signature of method: Step.findByService() is applicable for argument types: (java.lang.Integer) values: {3}"
However, when I change Step domain class field
ServicesGroup service
to simply
Long service
it works.
What's going on here?
Try it that way:
Step.findByService(ServicesGroup.get(3))
Try
grails clean
grails run-app
Then try again.
Something like Step.findByService([id: 3]) may work. It only cares about the ID anyway for the purposes of the SQL generation. In a lot of cases like this you can toss a fake map into there rather than the real thing, and save yourself some performance.
On the other hand, the abstraction breaks down a bit when you do this.

Resources