I've got a grails domain class I have to persist in Redis, something like this:
class A {
String one
Integer two
B three
E four
mapWith = "redis"
}
class B {
String name
}
enum E {
VALUE1, VALUE2
}
When I persist an instance of class A with the GORM .save() method, Redis saves it correctly except for the enum field "four".
As you can see the fact is known and reported here: http://jira.grails.org/browse/GPREDIS-3
Is there a good workaround to save Enum or something similar?
We're thinking about an array of String objects, what do you think?
I've got this mostly implemented but it doesn't work for Gemfire and I'm waiting until it's fixed for all the supported nosql providers before pushing the fix. As a workaround you can use the inList constraint with a combination of a persistent String property and a non-persistent get/set pair with the name of your current property, e.g.
class A {
String one
Integer two
B three
String fourString
void setFour(E e) {
fourString = e?.name()
}
E getFour() {
fourString ? E.valueOf(fourString) : null
}
static constraints = {
fourString inList: E.values()*.name()
}
static transients = ['fourString']
static mapWith = "redis"
}
Related
Using the map automatic creation on domain classes doesn't fill in transient properties:
class Address {
String street
String number
static transients = ["number"]
}
def address = new Address(street: "King's Street", number: "23")
println address.street //King's Street
println address.number //null
Is there any good reason for that? Grails domain instantiation overrides the default Groovy behaviour?
You can do it by two-way.
If you want to make transient a field, you need to bind it.
class Address {
String street
String number
static constraints = {
number bindable: true, nullable:true
}
static transients = ['number']
}
You can bind it using some getter method.
class Address {
String street
String number
String getDifferentNumber() { number }
static transients = ['differentNumber']
}
Hope it will help you. Enjoy.
Is there any good reason for that?
Yes. This has been the behavior since Grails 2.0.2. Properties which are not bindable by default are those related to transient fields, dynamically typed properties and static properties. There is some discussion about this at https://spring.io/blog/2012/03/28/secure-data-binding-with-grails.
Grails domain instantiation overrides the default Groovy behaviour?
Yes. This allows for doing a number of things which are common in a web app, like binding request parameters to a domain instance in a way that allows for a lot of flexibility needed to bind a bunch of Strings (request parameters) to a graph of objects.
If you really want to bind to a transient property all you have to do is configure the property to be bindable:
class Address {
String street
String number
static transients = ["number"]
static constraints = {
number bindable: true
}
}
See http://grails.github.io/grails-doc/2.4.5/ref/Constraints/bindable.html.
I hope that helps.
I'm new to Grails. I'm developing a web app that handles the records of a gymnasium, to make routines, exercises, etc.
I have this domain class Ejercicios:
class Ejercicios {
String nombreEjercicio
String idHoja
String descripcion
List<String> descripcionO
static hasMany = [descripcionO: Descripciones]
static transients = ['descripcionTrans']
String descripcionTrans
static mapping = {
id column: "idHoja"
version false
}
static constraints = {
nombreEjercicio maxSize: 45
idHoja blank: false
}
The database table has the default Grails id named "idHoja", and another attribute named "id_hoja"
The thing here is that when I make a JSON parse from the rest API, I need GORM to look for exercises via the "id_hoja" attribute, not the "idHoja" because it'll cause a mismatch.
I found the solution by myself!
The only thing I needed to was to make the JSON call with the name "idHoja" and that was it.
I recently inherited a Grails code base with a domain class called Name with (among others), the properties first and last to represent the first and last parts of a name, respectively. When writing a unit test which utilized this domain, I ran into some problems stemming from the names of these properties being the same as the first and last methods within Grails. Now, I can fix the problems by renaming the properties, but I was wondering if there is a way within Grails to use the property names first and last.
Namely, the error I was receiving was No signature of method: com.example.Name.first() is applicable for argument types: () values: []
Possible solutions: first(), first(java.lang.String), first(java.util.Map), list(), list(java.util.Map), print(java.lang.Object) when Grails attempts to apply a nullable: true constraint to the properties.
Here's the source of Name:
class Name {
String first
String middle
String last
static belongsTo = [person : Person]
static constraints = {
first(nullable:true)
middle(nullable:true)
last(nullable:true)
}
public static Name findOrCreate(String first, String middle, String last){
def name
name = Name.createCriteria().get{
and{
eq('first', first)
eq('middle', middle)
eq('last', last)
}
if(!name){
name = new Name()
name.first = first
name.middle = middle
name.last = last
}
return name
}
static mapping = {
cache true
}
}
You say that this error happens in the constraints block. In that case you may be able to get it working with an explicit delegate., i.e.
static constraints = {
delegate.first(nullable:true)
// and similarly for last
}
to force the first to be treated as a call into the constraints DSL rather than to the static GORM method.
I have a Grails domain called People, and I want to check that each People has childs or not. Childs are other People objects. Here is my domain structure:
class People implements Serializable {
static constraints = {
name (nullable : false, unique : true)
createdBy (nullable : false)
creationDate (nullable : false)
}
static transients = ['hasChild']
static mapping = {
table 'PEOPLE'
id generator: 'sequence', params : [sequence : 'SEQ_PK_ID']
columns {
id column : 'APEOPLE_ID'
parentPeople column : 'PARENT_PEOPLE_ID'
}
parentPeople lazy : false
}
People parentPeople
String name
String description
Boolean hasChild() {
def childPeoples = People.createCriteria().count {
eq ('parentPeople', People)
}
return (childPeoples > 0)
}
}
But I cannot call people.hasChild() at anywhere. Could you please helpe me on this? Thank you so much!
It's because in eq ('parentPeople', People), Grails can't understand what "People" is (it's a class). You should replace "People" by this. For example:
static transients = ["children"]
def getChildren() {
def childPeoples = People.findAllByParentPeople(this, [sort:'id',order:'asc'])
}
Another way to get the same result is to use Named Queries. It seems more concise and was created specifically for this purpose. I also like it because it fits the pattern of static declarations in a domain model and it's essentially a criteria, which I use throughout my applications. Declaring a transient then writing a closure seems a bit of a work-around when you can declare named queries ... just my opinion.
Try something like this:
static namedQueries = {
getChildren {
projections {
count "parentPeople"
}
}
}
I have to implement map values in my Grails app.
I have a class that can contain 0..N OsmTags, and the key is unique.
In Java I would model this with a Map in each object, but I don't know how to map classes in Grails.
So I defined this class:
class OsmTag {
/** OSM tag name, e.g. natural */
String key
/** OSM tag value, e.g. park */
String value
static constraints = {
key blank:false, size:2..80,matches:/[\S]+/, unique:false
value blank:false, size:1..250,matches:/[\S]+/, unique:false
}
}
That works ok, but it's actually quite ugly because the tag key is not unique.
Is there a better way to model this issue?
Cheers
If your tags are simple strings, then you can use a map directly.
class Taggable {
Map tags // key : String, value : String
}
If I understand your question correctly, then you want to ensure that each tag is unique within a particular instance of the tagged entity?
Assume that the entity to which the tags are attached is named Taggable, then
you can enforce this requirement using a custom constraint:
class Taggable {
static hasMany = [ tags: OsmTag ]
}
class OsmTag {
static belongsTo = [ taggable: Taggable ]
/** OSM tag name, e.g. natural */
String key
/** OSM tag value, e.g. park */
String value
static constraints = {
key(blank:false, size:2..80,matches:/[\S]+/, unique:false,
validator: { val, obj ->
if (obj.taggable.tags.key.count(val > 1)) {
return false
}
}
)
value(blank:false, size:1..250,matches:/[\S]+/, unique:false)
}
}
If you're looking for a NoSQL solution, you could try using MongoDB with Grails. The most recent version (1.4) supports Geospatial indexing and querying.