GORM: saving a manyTomany relationship - grails

just trying to persist a relationship between GORM entities, and an overflow error appends on mapping during save.
1) I create a manyTomany relationship between User and DataStore:
User entity:
...
static belongsTo = DataStore
static hasMany = [groups: Groups,dataStore:DataStore]
Profile profile
Contacts contact
DataStore dataStore
...
DataStore entity:
...
static belongsTo = [service:Service]
static hasMany = [users:User]
Service service
List<User> users
...
2) Calling the service from a controller to save datas:
UserRole.create user, roleCustomer, true
UserRole.create user, roleAdmin, true
dataStoreService.createDS('ds',profile.service,user)
3) Service logic:
#Transactional
def createDS(ds,service,user) {
def key = service.domainkey
if (user && key) {
DataStore ds = new DataStore(ds:ds)
ds.validate() ? ds.save(flus:true) : ds.errors.allErrors.println()
ds.addToUsers(user).save(flush:true)
service.addToDataStore(ds).save(flush:true)
user.setDataStore(ds)
...}
4) The weird error i need to solve:
Stacktrace follows:
org.codehaus.groovy.grails.web.servlet.mvc.exceptions.ControllerExecutionException: Executing action [sendOrder] of controller [$$.StoreController] caused exception: Runtime error executing action
at grails.plugin.cache.web.filter.PageFragmentCachingFilter.doFilter(PageFragmentCachingFilter.java:195)
at grails.plugin.cache.web.filter.AbstractFilter.doFilter(AbstractFilter.java:63)
at net.bull.javamelody.JspWrapper.invoke(JspWrapper.java:149)
at net.bull.javamelody.JdbcWrapper$DelegatingInvocationHandler.invoke(JdbcWrapper.java:259)
at net.bull.javamelody.MonitoringFilter.doFilter(MonitoringFilter.java:202)
at net.bull.javamelody.MonitoringFilter.doFilter(MonitoringFilter.java:175)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
at java.lang.Thread.run(Thread.java:680)
Caused by: org.codehaus.groovy.grails.web.servlet.mvc.exceptions.ControllerExecutionException: Runtime error executing action
... 9 more
Caused by: java.lang.reflect.InvocationTargetException
... 9 more
Caused by: java.lang.StackOverflowError
at org.apache.commons.validator.EmailValidator.stripComments(EmailValidator.java:246)
at org.apache.commons.validator.EmailValidator.isValid(EmailValidator.java:95)
Any help please?

EDIT
After looking again at the stack trace the problem has nothing to do with Melody (maybe? maybe not?) but let us know what was wrong).
Check the email reference of the User (Not sure in which sub-domain class it is located, maybe contact class? print it or use a debugger to inspect the domain values and then double-check your constraints) . If the email issue is not related to your domain classes, then double-check again melody...
org.apache.commons.validator.EmailValidator.isValid(EmailValidator.java:95)....
-- Still double-check what Melody is doing.
If the problem was related to Melody, please let us know, just for personal information. I've seen so many random issues from people using that plugin, it looks useful but buggy.

You have the variable dataStore defined twice: once in your hasMany and once as a straight reference.
Try:
User entity:
...
static belongsTo = [datastore: DataStore]
static hasMany = [groups: Groups,dataStores:DataStore]
Profile profile
Contacts contact
...

just redone my model following hibernate doc:
class User implements Serializable {
static hasMany = [dataStores:DataStore,contacts:Contacts,groups: Groups]
Profile profile
Contacts contacts
List<DataStore> dataStores
with contraint: dataStores nullable:true
And DS entity:
class DataStore implements Serializable{
static hasMany = [users:User,contacts:Contacts]
static belongsTo = [service:Service]
Service service
User users
removes definetely the several overflows and keeps the model reliable.

Related

Grails Elasticsearch plugin issues

I am new to Elasticsearch and am using the revived grails plugin "elasticsearch:0.0.4.6".
I wanted to implement a search for a User by their firstName, surname or username, which returns the full domain instance.
I have a 2 domain classes:
User:
class User {
String firstName
String surname
static hasOne = [profile:Profile]
static hasMany = [friends:User]
static mappedBy = [ friends: 'friends' ]
static searchable = {
profile component:true
only = ['firstName', 'surname', 'profile']
}
...
Profile:
class Profile {
String username
String status
byte[] photo
static belongsTo = [user:User]
static searchable = true
...
}
I made the classes "searchable = true" and then created the following search:
def res = User.search("${params.friendSearch}").searchResults
This found the correct instances, but now when a user adds a photo to their profile, it suceeds but I recieve a never ending loop of the following error:
ERROR index.IndexRequestQueue - Failed bulk item: MapperParsingException[failed to parse [photo]]; nested: NumberFor
matException[For input string: the photos base64inputstring
I dont really get what is happening, but i figure it must be something to do with elasticsearch being unable to index the photo data. Can somebody provide an explanation?
I then experimented with searchables custom mapping options -
profile index:'no'
all=false
excludeFromAll = true
etc
Nothing worked. Eventually I added
only = ['username']
and it stopped the error from occuring and allowed me to find users based on the criteria i mentioned above. However, because of the "only" limit, it means that the User instances returned by the seach have a photo property equal to null, but i need this value!
What am i doing wrong? Can anyone advise me on the best course of action to take or any misunderstandings i have about Elasticsearch? Thanks
I think you might have to exclude the byte property photo from the searchable fields like so:
class Profile {
String username
String status
byte[] photo
static belongsTo = [user:User]
static searchable = {
except = ['photo']
}
This will exclude the property photo from being indexed and search. Hence the output of converting the byte format to string format will not fail.
Also maybe you might need a custom convertor to change the byte(string) to something more usable in the results?

Grails Multiple data source: org.springframework.beans.factory.NoUniqueBeanDefinitionException

I recently posted a question about multiple data sources. Things were going well until I hit this issue:
Controller
def doSomething() {
def user=userService.getCurrentUser()
}
Service
class UserService {
def getCurrentUser() {
def principal = springSecurityService.principal
String username = principal.username
return find(username)
}
def find(String user) {
return User.find{username==user}
}
}
This had been working previously on single DataSource but now with both enabled I see this on the browser:
Error 500: Internal Server Error URI /xxx/xxx Class
org.springframework.beans.factory.NoUniqueBeanDefinitionException
Message No qualifying bean of type
[org.springframework.transaction.PlatformTransactionManager] is
defined: expected single matching bean but found 3:
transactionManager,transactionManager_countrycity,$primaryTransactionManager
Okay this is now resolved.
I think I found the issue: under grails 3 with multiple data sources if you have this import :
import org.springframework.transaction.annotation.Transactional
You will run into the above problems:
If you how ever have :
import grails.transaction.Transactional
things will work as expected. I hadn;t paid attention and let ide choose wrong declaration

Grails find by property

Okay, I am trying to find all of my Employee that have a given role... However no matter what I try I end up getting the same exception thrown...
enum Role {
SFC("State Fitness Coordinator"),
TRAINING("Training"),
DFC("District Fitness Coordinator"),
final String longName
private Role(String longName) {
this.longName = longName
}
}
class Employee {
static hasMany = [roles: Role]
static constraints = {
}
}
The first Thing I tried was Employee.findAllByRoles(Role.DFC)
Then I tried:
Employee.findAll("FROM Employee e WHERE e.roles IN (:role)", [role: [Role.DFC]])
as well as
Employee.withCriteria {
'in'('roles', [Role.DFC])
}
all resulting in
Class
java.sql.SQLException
Message
Missing IN or OUT parameter at index:: 1
Any direction would be much appreciated.
with grails 2.3.8 and H2
Employee.findAll("FROM Employee e WHERE :role in elements(e.roles) ", [role: Role.DFC.toString()])
this works… even if I think that Role could be a real Domain simplifying all operations
I think the problem is that Role is an enum. Are you sure you want to make it an enum?
I recommend making it a class since new roles might be added. If so, you can easily add a record using bootstrap or SQL query without making a new build to production.
class Role {
String roleName
String description
}
In Bootstrap:
Role sfc = new Role("SFC","State Fitness Coordinator")
Role sfc = new Role("TRAINING," "Training")
Role sfc = new Role("DFC", "District Fitness Coordinator")
N.B. Please make sure you are not using spring security plugin which has its own 'Role' class. If so, please change the name of your 'Role' class to something like 'EmployeeRole'

Grails loading data once

I have these 2 domains
class Country {
String name
static hasMany = [cities:City]
}
class City {
String name;
static belongsTo = [country: Country]
}
The data contained in these 2 tables is relatively big, and they're used in all the screens,
every time i choose a country i have to reload all its cities.
How can I load the data only once in memory so i can access it faster in all the screens.
I tried putting cities for eager fetching, and tried using cache plugin.
Thank you
You can configure both domain classes to be cached automatically and also cache the cities relation in Country:
class Country {
String name
static hasMany = [cities:City]
static mapping = {
cache true
cities cache:true
}
}
class City {
String name
static belongsTo = [country: Country]
static mapping = {
cache true
}
}
Caching is often a good strategy, but remember that caches have expiry parameters so if left idle your app may reload from the DB again. Depending on your cache provider you'll have to tune this, eg For ehcache edit your ehcache.xml in the grails config folder and set (cache name is the same as your Domain class including package name):
<cache name="Country" maxElementsInMemory="1000" timeToIdleSeconds="0" timeToLiveSeconds="0"/>
You should also move the query into a service, the service is by default singleton scoped and the service method also cachable.
An alternative is to store them in application scope such as in your Bootstrap.groovy run the query and assign the results:
servletContext.countries = Country.list()
Retrieve them in the same way, eg
in a controller:
List<Country> countries = servletContext.countries
or gsp:
<g:each var="country" in="${application.countries}">
${country}
</g:each>
If you have eager fetching on then you should see no DB hits.

Overcoming "No owner defined between domain classes" in Grails many-to-many relationship

I was following the "Grails in Action" book in order to create the following scenario.
A map belongs to one or many mapsets. A mapset can contain one or many maps. Both belong to a user.
So, what I did was:
Map.groovy:
static hasMany = [ sets : Mapset ]
static belongsTo = [ user : User, set : Mapset ]
Mapset.groovy:
static hasMany = [ maps : Map ]
static belongsTo = [ user : User ]
User.groovy:
static hasMany = [ maps : Map, sets: Mapset ]
Still, I receive this error when running the app:
Caused by: org.codehaus.groovy.grails.exceptions.GrailsDomainException: No owner defined between domain classes [class at.package.Mapset] and [class at.package.Map] in a many-to-many relationship. Example: static belongsTo = at.package.Map
It doesn't change anything if I write the fully qualified class name for Map.
Whoops, this is weird. The following the trick:
In Map.groovy:
static belongsTo = [ User, Mapset ]
I'd probably keep this as an answer instead of deleting the question because there's no reference for this error message on SO yet

Resources