Grails BootStrap: No signature of method: *.addTo* applicable - grails

I have two domain classes: User
class User {
String username
String password
String email
Date dateCreated
Date lastUpdated
// static belongsTo = [profile: Profile]
static constraints = {
username size: 3..20, unique: true, nullable: false, validator: { _username ->
_username.toLowerCase() == _username
}
password size: 6..100, nullable: false, validator: { _password, user ->
_password != user.username
}
email email: true, blank: false
// profile nullable: true
}
}
and Profile:
class Profile {
String firstName
String middleName
String lastName
byte[] photo
Date dateCreated
Date lastUpdated
static belongsTo = [User]
static constraints = {
firstName blank: false
middleName nullable: true
lastName blank: false
photo nullable: true, maxSize: 2 * 1024**2
}
}
A profile can belong to only one user and a user can have (or belong to?) only one profile. When I try to create the objects in BootStrap.groovy in the current setup I get an error saying that the addTo() method does not exist. I don't really know what I am doing wrong. This is how I am creating them in BootStrap.groovy:
User arun = new User(username: 'arun', password: 'password', email: 'arun#email.com').save(failOnError: true)
Profile arunProfile = new Profile(firstName: 'Arun', lastName: 'Allamsetty').addToUser(arun).save(failOnError: true)
Can someone please point out the mistake(s). I am sure it's silly.

A strict bi-directional one-one relationship is required as you have requested for:
A profile can belong to only one user and a user can have (or belong to?) only one profile
Three modifications are mainly required in domain classes:
//User.groovy
static hasOne = [profile: Profile]
static constraints = {
profile unique: true
}
//Profile.groovy
User user
Above is a bi-directianl one-one relationship. You do not need addTo* anymore while creating each of them.
Profile arunProfile = new Profile(firstName: 'Arun', lastName: 'Allamsetty')
User arun = new User(username: 'arun', password: 'password',
email: 'arun#email.com',
profile: arunProfile).save()

Related

Convert Sql Query to Grails/Gorm query

How do I convert the following SQL query to Grails/Gorm? Can this be done with a basic query? I would like to avoid using Criteria, Projections and HQL to keep it consistent with the structure of the other queries in my code base (which are basic queries).
SELECT dealer_group_user_dealer_users_id, COUNT(user_id)
FROM db.dealer_group_user_user
GROUP BY dealer_group_user_dealer_users_id;
And is it possible to perform the query in the gsp page to display the result for a specific user_id as opposed to running the query in the controller?
To update from a comment made, below is my domain classes.
class DealerGroupUser extends User{
static hasMany = [dealerUsers: User]
static constraints = {
}
}
class User {
transient authService
Boolean active = true
String firstName
String lastName
String title
String username
String emailAddress
String passwordHash
Date lastLoginTime
Date dateCreated
Date lastUpdated
Retailer dealer
Client client
Date passwordUpdated
Long dealerUser
Boolean isReadOnlyClientManager = false
String regionClientManager
// Transient properties
String fullName
String password
static transients = ['fullName', 'password']
static mapping = {
//permissions fetch: 'join'
sort firstName: 'asc' // TODO: Sort on fullName
}
static hasMany = [roles: Role, permissions: String]
static constraints = {
// NOTE: If a username is not provided, the user's email address will be used
firstName maxSize: 30, blank: false
lastName maxSize: 30, blank: false
title maxSize: 50, blank: false, nullable: true
username blank: false, unique: true
emailAddress email: true, unique: false, blank: false
passwordHash blank: false
lastLoginTime nullable: true
active nullable: true
dealer nullable: true
client nullable: true
passwordUpdated nullable: true
dealerUser nullable: true
regionClientManager nullable: true
}
void setEmailAddress(String emailAddress) {
if (EmailValidator.instance.isValid(emailAddress)) {
this.emailAddress = emailAddress
if (!username) {
username = emailAddress
}
}
}
static namedQueries = {
dealerGroupUsers {
eq 'class', 'com.db.torque.DealerGroupUser'
}
}
Integer setPassword(String plainTextPassword) {
plainTextPassword = plainTextPassword?.trim()
if (plainTextPassword) {
if (!plainTextPassword.matches("^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=\\S+\$).{8,}\$")){
return -1
}
String previousPassword = this.passwordHash
String newPassword = authService.encrypt(plainTextPassword)
if (previousPassword != newPassword) {
this.passwordHash = newPassword
return 1
}
else {
return -2
}
}
return -1
}
#Transient
public static List<User> findAllByRolesContains(Role role) {
return User.executeQuery("""
SELECT u
FROM User as u
WHERE :role IN elements(u.roles)
""", [role: role])
}
String fullName() {
return "${firstName} ${lastName}"
}
String toString() {
return fullName()
}
}
SELECT dealer_group_user_dealer_users_id, COUNT(user_id)
FROM db.dealer_group_user_user
GROUP BY dealer_group_user_dealer_users_id;
In your user class you have :
Retailer dealer
So lets start from the beginning what is query doing, listing users from user then getting a count of how many times user appears on Retailer domain class ?
The best way to do this would
be
String query = """ select
new map(
u.id as userId,
(select count(d) from DealerGroupUser d left join d.dealerUsers du where du=u) as userCount
)
From user u order by u.id
"""
def results = User.executeQuery(query,[:],[readOnly:true]
This should do what you are doing I think.
And is it possible to perform the query in the gsp page to display the
result for a specific user_id as opposed to running the query in the
controller?
Views are presentation layer and hardcore work should be kept out of it - if needed to use a TagLib call.
Controllers although used in grails examples and rolled out as part of defaults to make things easier also not the best place. You should be doing that in a service which is injected in a controller and presented in view as the actual model of what is needed.
That is the proper way - GSP have a runtime size - keep it short, keep it sweet

Error loading plugin manager in Grails/Groovy

I'm working on a simple grails project when I encountered a problem. I have done lot of research but I haven't found the right answer.
The thing is I have 3 domain classes namely Inventory, User and Movement and the relationship between them is one-to-many for Inventory and Movement and the same for User and Movement so Movement is pretty much in the middle. I managed to connect the Inventory and Movement well but the other relationship shows an error below.
Error |
Error loading plugin manager: Property [movements] in class [classcom.inventory.User] is a
bidirectional one-to-many with two possible properties on the inverse side.
Either name one of the properties on other side of the relationship [user] or use the
'mappedBy' static to define the property that the relationship is mapped with.
Example: static mappedBy = [movements:'myprop'] (Use--stacktrace to see the full trace)
| Error Forked Grails VM exited with error
This are my domain classes:
Users:
class User {
String userID
String fullName
String position
Department department
String toString(){
fullName
}
static hasMany = [inventories: Inventory, movements: Movement]
static constraints = {
userID blank: false, unique: true
fullName blank: false
position()
department()
movements nullable: true
}
}
Movement:
class Movement {
User oldUser
User newUser
Inventory inventoryID
Date movementDate
User userResponsible
//static belongsTo = User
static constraints = {
inventoryID blank: false
oldUser blank: false
newUser blank: false
movementDate()
userResponsible blank: false
}
}
Inventory:
class Inventory {
String inventoryID
String code
String description
String serial_num
Date purchase_date
byte[] image
Date record_date
String remarks
Type type
Brand brand
User user
static hasMany = [movements: Movement]
String toString(){
"$inventoryID, $type"
}
static constraints = {
inventoryID blank: false, unique: true
code blank: false
description nullable: true, maxSize: 1000
serial_num blank: false
purchase_date()
image nullable: true, maxSize: 1000000
record_date()
remarks nullable: true, maxSize: 1000
type()
brand()
user()
}
}
Any idea how to solve the error..??
The problem here is that gorm is unable to distinguish between the newUser and the oldUser on your Movements class. Try adding a mappedBy section and adding another part to your hasMany property to your user class, below is an example that should work:
class User {
String userID
String fullName
String position
Department department
String toString(){
fullName
}
static hasMany = [inventories: Inventory, movementsByOldUser: Movement, movementsByNewUser: Movement]
static mappedBy = [movementsByOldUser: 'oldUser', movementsByNewUser: 'newUser']
static constraints = {
userID blank: false, unique: true
fullName blank: false
position()
department()
movements nullable: true
}
}
For some documentation reference see: http://www.grails.org/doc/2.2.x/ref/Domain%20Classes/mappedBy.html

How to have multiple One-to-One relationships between three domain classes

As a follow up question to this, I want to have a User domain class which has an optional one-to-one relationship with BasicProfile domain class, User being the owner which may or may not have a profile. I have this part figured out. What I also want is an optional one-to-one relationship between the AcademicProfile domain class and the User, AcademicProfile being the owner, such that an AcademicProfile may or may not have a User. When I try to replicate this the way I did the first one-to-one relationship, it does not work. Here are my classes.
class User {
String username
String password
String email
AcademicProfile academicProfile
Date dateCreated
Date lastUpdated
static hasOne = [basicProfile: BasicProfile]
static constraints = {
username size: 3..20, unique: true, nullable: false, validator: { _username ->
_username.toLowerCase() == _username
}
password size: 6..100, nullable: false, validator: { _password, user ->
_password != user.username
}
email email: true, blank: false
basicProfile nullable: true
}
}
class BasicProfile extends Profile {
User user
Date dateCreated
Date lastUpdated
}
class AcademicProfile extends Profile {
String dblpId
String scholarId
String website
Date dateCreated
Date lastUpdated
static hasOne = [user: User]
static hasMany = [publications: Publication]
static constraints = {
dblpId nullable: true
scholarId nullable: true
website nullable: true, url: true
publications nullable: true
user nullable: true
}
}
class Profile {
String firstName
String middleName
String lastName
byte[] photo
String bio
static constraints = {
firstName blank: false
middleName nullable: true
lastName blank: false
photo nullable: true, maxSize: 2 * 1024**2
bio nullable: true, maxSize: 500
}
static mapping = {
tablePerSubclass true
}
}
When I run it, I get the error: Field error in object 'org.academic.User' on field 'academicProfile': rejected value [null];. I don't understand what I am doing wrong.
You'll have to add nullable:true constraint for AcademicProfile academicProfile in User class as you mentioned that you need an 'optional' relationship between AcademicProfile & User.
The error itself is self explanatory though, that you can't create a User class's instance, without providing the academicProfile property a non-null value.

Relationships between Grails domain classes with inheritance

I have the following class. In src/groovy,
class Profile {
String firstName
String middleName
String lastName
byte[] photo
String bio
}
The domain classes BasicProfile and AcademicProfile extend Profile.
class BasicProfile extends Profile {
User user
Date dateCreated
Date lastUpdated
static constraints = {
firstName blank: false
middleName nullable: true
lastName blank: false
photo nullable: true, maxSize: 2 * 1024**2
bio nullable: true, maxSize: 500
}
static mapping = {
tablePerSubclass true
}
}
class AcademicProfile extends Profile {
User user
String dblpId
String scholarId
String website
Date dateCreated
Date lastUpdated
static hasMany = [publications: Publication]
static constraints = {
importFrom BasicProfile
dblpId nullable: true
scholarId nullable: true
website nullable: true, url: true
publications nullable: true
}
static mapping = {
tablePerSubclass true
}
}
Then there is a Publication class.
class Publication {
String dblpId
String scholarId
String title
String description
Date publicationDate
int citations
Date dateCreated
Date lastUpdated
static belongsTo = [AcademicProfile]
static hasOne = [publisher: Publisher]
static hasMany = [academicProfiles: AcademicProfile]
static constraints = {
dblpId nullable: true
scholarId nullable: true
title blank: false, maxSize: 100
description nullable: true, maxSize: 500
publicationDate: nullable: true
academicProfiles nullable: false
}
}
Finally, I have a User class.
class User {
String username
String password
String email
Date dateCreated
Date lastUpdated
static hasOne = [basicProfile: BasicProfile, academicProfile: AcademicProfile]
static constraints = {
username size: 3..20, unique: true, nullable: false, validator: { _username ->
_username.toLowerCase() == _username
}
password size: 6..100, nullable: false, validator: { _password, user ->
_password != user.username
}
email email: true, blank: false
basicProfile nullable: true
academicProfile nullable: true
}
}
My questions are as follows.
I want a relationship where each User may optionally have a Profile (either BasicProfile or AcademicProfile). I tried static hasOne = [profile: Profile] but I got errors saying Profile does not agree to the hasOne relationship. So the current setup I have is a workaround. Is there no way a user can have one Profile be it BasicProfile or AcademicProfile?
Secondly, in the current setup, I get the error: Invocation of init method failed; nested exception is org.hibernate.MappingException: An association from the table academic_profile_publications refers to an unmapped class: org.academic.AcademicProfile when I try to run it. A Google search tells me that this is a problem with classes which are inheriting from other classes. So technically, if I don't have a hasMany relationship in Publication with AcademicProfile, it should work without any issues. But I don't want that. Because a publication has many authors (AcademicProfiles in my case) and an author may have many publications. So is there a way to fix this?
You're not using Hibernate inheritance - that requires that all of the classes be mapped. You're just using regular Java/Groovy inheritance where you inherit properties and methods from base classes. But Hibernate isn't aware of that, so it can't do queries on the unmapped base class.
I'm not sure why it's complaining about AcademicProfile, but it could be a secondary bug caused by the core issue.
I find Hibernate inheritance to be way too frustrating to use in most cases, so I use this approach when there is shared code.
It should work if you move Profile to grails-app/domain. Once you do that you should move the tablePerSubclass mapping config to the base class and only specify it once.

Grails searchable plugin with hasMany

I am using grails searchable plugin to search my domain classes. However, I cannot yet search by my hasMany (skills and interests) fields even though they are of the simple type String. This is my domain class:
class EmpactUser {
static searchable = [except: ['dateCreated','password','enabled','accountExpired','accountLocked','passwordExpired']]
String username
String password
boolean enabled = true
boolean accountExpired
boolean accountLocked
boolean passwordExpired
String email
String firstName
String lastName
String address
String phoneNumber
String description
byte[] avatar
byte[] resume
Date dateCreated
static hasMany = [
skills : String,
interests : String, // each user has the ability to list many skills and interests so that they can be matched with a project.
]
static constraints = {
username blank: false, unique: true
password blank: false
email email: true, blank: false
firstName blank: false
lastName blank: false
description nullable: true
address nullable: true
avatar nullable: true, maxSize: 1024 * 1024 * 10
resume nullable: true, maxSize: 1024 * 1024 * 10
phoneNumber nullable: true, matches: "/[(][+]d{3}[)]d+/", maxSize: 30
}
}
This is the code I am using to search:
def empactUserList = EmpactUser.search(
searchQuery,
[reload: false, result: "every", defaultOperator: "or"])
Am I missing something?
Thanks,
Alan.
Searchable has trouble recognising hasMany relations with Strings. A workaround is to create a new domain object which "belongs to" the parent object, and make a transient variable in the parent class. The following code works as an alternate to the example given in documentation.
class Article {
static searchable = {
root true
keywords (component:true)
}
static transients = ['keywords']
Set<ArticleKeyword> getKeywords() {
ArticleKeyword.findAllByArticle(this) as Set
}
}
class ArticleKeyword {
static searchable = { root false}
static constraints = {
}
String text
static belongsTo = [article:Article]
static mapping = {
text type: 'text'
}
}

Resources