I'm recreating a working Grails 2.2.5 application in Grails 4 in order to get to know the new version (with the view to migrating all 2.2.x apps over in due course). So far I've only moved a handful of Groovy classes from the src directory over, but I'm running into a compile problem with a class which is apparently no longer present in Grails 4, org.codehaus.groovy.grails.commons.DefaultGrailsDomainClass. I use this to iterate through the persistent properties of a domain class (with persistentProperties). How would I do this in Grails 4? I.e., get all the persistent properties of a domain class?
DefaultGrailsDomainClass is indeed deprecated since Grails 3.3.2 in favor of the mapping context API. Fortunately, it is quite straightforward to replace the deprecated implementation.
Inject the grailsDomainClassMappingContext bean in your service or controller:
def grailsDomainClassMappingContext
then get the persistent entity by providing its name:
def entity = grailsDomainClassMappingContext.getPersistentEntity(domainObjName)
where domainObjName is a string and entity is an instance of org.grails.datastore.mapping.model.PersistentEntity. You can also get a specific property by using:
def property = entity.getPropertyByName(propertyName)
where propertyName is a string and property is an instance of org.grails.datastore.mapping.model.PersistentProperty.
The interfaces PersistentEntity and PersistentProperty offer a variety of useful methods to cover many uses.
Related
Contemplating upgrade of a plugin from Grails 3.2.11 to Grails 3.3.2 while accomodating the slashing change in the domain class API. PersistentProperty replaces GrailsDomainClassProperty but has no isPersistent() method.
How do I find out programmatically if a domain class property is transient? Does PersistentEntity return transient properties at all?
(I tend to use transient properties a lot. Great for productivity.)
PersistentEntity.getPersistentProperties() will give you list of properties to be persisted - meaning it doesn't include transient properties. You can try:
GrailsClassUtils.getStaticPropertyValue(MyDomain, "transients")?.contains("myPropertyName")
I have a domain class which extends another groovy class with same name but in different package in a different library.
The problem is when I modify instances on the domain class, it is not marked as dirty & hence changes are not persisted.
I have read that grails 3 release has some enhancements to dirty checking & this could be a bug or I am missing something.
New objects are saved properly without any issues, I have used isDirty() method on modified domain object as well as modified properties & both return false. Objects are attached to the session, confirmed with isAttached().
To reproduce, I created a test project with following code & tried updating the object from default grails views that are generated using scaffolding, but still the changes are not persisted.
Note: I have done similar stuff in Grails 2.4 & it used to work.
Domain class is as follows:
package com.perseus
class Derived extends Base{
static constraints = {
name blank: false, nullable: false
}
}
Base class in src/main/groovy:
package com.perseus
class Base implements Serializable {
private static final long serialVersionUID = 1L
String name
}
Controller
package com.perseus
class DerivedController {
static scaffold = Derived
}
Link to github project.
Isssue: Model is not marked dirty, even if it has been modified. This happens when a model class extends another groovy class.
How to reproduce:
Run the app.
Create a new model object (model name is Derived)
Modify the object using edit view & click Update.
You will see that modifications are not persisted.
Finally I found a reference here which explains the reason for failure to update dirty check status.
I added #DirtyCheck annotation and it solved the problem.
However this has a negative impact on the design of our libraries.
We have separate projects for each category:
Business model classes
Business logic classes
User Interface
The idea is to have modules completely independent of each other. So model & business logic liraries can be used by any UI technology. Now the problem is that I had to add gorm dependency to my business model project for the annotation.
compile 'org.grails:grails-datastore-gorm:6.1.7.RELEASE'
Design wise we like our model classes in a project completely independent of UI or persistent technologies like hibernate. So that these model classes can be used in variety of different projects without any additional dependencies. And we achieved this with grails so far by creating a new class that extends actual model class in our library
Is there any way I can solve this problem, without modifying the base class?
In short, model classes (POJO) are now dependent on grails framework, whereas in earlier versions they were not.
I am currently migrating a Grails 2.4 project to Grails 3.0.10 or 3.1.0.M3.
In Grails 2.4, the following method is a workaround that allows me to detect whether a Domain Class features a composite primary key:
void isCompositePrimaryKey(GrailsDomainClass targetClass) {
def binder = new GrailsDomainBinder()
def idMapping = binder.getMapping(targetClass).identity
return idMapping instanceof org.codehaus.groovy.grails.orm.hibernate.cfg.CompositeIdentity
}
I cannot find a way to detect this in the Public API.
Though GrailsDomainClass still exists in the implementation source code, I cannot seem to access it from my project nor can I find the old CompositeIdentity.
An alternative strategy could be via targetClass.getIdentifier().getType()
but I cannot find any documentation on how to detect a composite key using the identity type.
Solved this simply by adding an additional explicit (non-transitive) dependency to build.gradle for the Hibernate 4 GORM implementation package.
(I determined the package and version by looking in the local gradle files cache but gradle dependencies would also have worked.)
Added to build.gradle:
compile 'org.grails:grails-datastore-gorm-hibernate4:5.0.0.RC2'`
This allows access to the internal API, then the above method still works.
NB. The GORM developers also advise that there is existing GORM API for this, via the PersistentEntity and MappingContext classes without using GrailsDomainClass.
I used to access grails 2 constraints in my gsp like this :
${MyDomainClass.constraints.myProperty.inList.collect{it.name()}}
It doesn't work in Grails 3 anymore
In Grails 3.0 domain and command objects are using the trait grails.validation.Validateable (Source can be found here). That trait gives you access to the constraints by providing the following method.
static Map<String, ConstrainedProperty> getConstraintsMap();
In order to access the constraints you call that method on your domain or command object. The following example accesses the nullable constraint on a domain objects property called day.
domainObject.getConstraintsMap()['day']['nullable']
That way, which was valid in Grails 2, still works...
grailsApplication.getArtefact('Domain',
'MyDomainClass').getConstrainedProperties().myProperty.inList.collect{it.name()}
see GrailsDomainClass API
before Grails 2.x we used an abstract class to model shared domain properties. This worked perfect but now when using Grails 2.x is see no way of creating shared domain properties and methods. When i use an abstract class and let my domain classes extend that abstract class i get one big database table.
Is there a alternative way of creating shared domain properties / methods?
Docs says that you need to move your base class into the /src/groovy at this case