I am doing this:
class Face {
String name
def ears = []
Nose nose
void addEar(Ear ear){
ears << ear
}
}
class Nose {
String name
}
class Ear {
String name
}
And on Bootstrap.groovy:
def nose = new Nose(name: "Nose")
nose.save()
def leftEar = new Ear(name: "Left ear")
leftEar.save()
def rightEar = new Ear(name: "Right ear")
rightEar.save()
def face = new Face(name: "Face", nose: nose)
face.addEar(leftEar)
face.addEar(rightEar)
face.save()
When I run the app and enter dbconsole to see the tables, face has a reference to its nose and I can read its name "Face", but it has no reference to its ears. How should I save this list so I can access it later?
Or in case it's actually saved somewhere, where? How should I access it?
Take a look at Grails documentation about associations. Focus on 'One to many' and 'Many to many' associations. You can find nice examples on how to declare association (static hasMany property) and add elements to them (addTo* method).
Related
Starting with a github repo that demonstrates how to use GORM outside of Grails, I am attempting to use dynamic finders so that I can look up a particular domain object by one of its properties. In this example, we have this person object in groovy as such:
package domain
import grails.gorm.annotation.Entity
import org.grails.datastore.gorm.GormEntity
#Entity
class Person implements GormEntity<Person> {
String firstName
String lastName
static mapping = {
firstName blank: false
lastName blank: false
}
}
Now lets say I want to look up a person by last name. I should be able to use the GORM-enhanced Person entity method findByLastName. I'm able to compile the code that attempts this, but when I call it at runtime, the method is not found.
I added a test method to PersonSpec.groovy that looks like this:
#Rollback
def "person can be found by last name"() {
when:
def p = new Person(firstName: 'Scott', lastName: 'Ericsson')
p.save(flush: true)
def foundPerson = p.findByLastName('Ericsson')
then:
foundPerson.firstName == 'Scott'
}
I get this error when the test is run:
domain.PersonSpec > person can be found by last name FAILED
groovy.lang.MissingMethodException at PersonSpec.groovy:32
The test method above it creates and saves a person record successfully, so some aspects of GORM functionality are working. But dynamic finder functionality is not being properly applied at run time, even though the compiler thinks everything looks good.
My entire build.gradle is this:
apply plugin: 'groovy'
repositories {
jcenter()
}
dependencies {
compile "org.hibernate:hibernate-validator:5.3.4.Final"
compile "org.grails:grails-datastore-gorm-hibernate5:7.0.0.RELEASE"
runtime "com.h2database:h2:1.4.192"
runtime "org.apache.tomcat:tomcat-jdbc:8.5.0"
runtime "org.apache.tomcat.embed:tomcat-embed-logging-log4j:8.5.0"
runtime "org.slf4j:slf4j-api:1.7.10"
testCompile 'org.spockframework:spock-core:1.1-groovy-2.4'
}
Does anyone know what I am missing?
So I've been struggling with this for a couple of days, and wouldn't you know as soon as I post the question I figure it out almost instantly. It's simple--I need to use findByLastName method statically on the Person object instead of a person instance. The code that works in PersonSpec looks like this now:
#Rollback
def "person can be found by last name"() {
when:
def p = new Person(firstName: 'Scott', lastName: 'Ericsson')
p.save(flush: true)
def foundPerson = Person.findByLastName('Ericsson')
then:
foundPerson.firstName == 'Scott'
}
I have two domain classes (simplified) which are related by a Many-to-Many relationship.
A Team can have many Players and a Player can belong to many Teams.
When i call the 'save' action of the Team controller :
A player gets saved in the table. (as expected)
A Team gets saved in the table. (as expected)
When i print team.players and player.teams, i see the correct output (See code below)
Nothing is saved in the relationship table (TEAM_PLAYERS). Why is this happening? Do i need to make entries in the join table myself? If this table is not getting updated, how am i seeing the correct output for point 3. ?
Team.groovy is :
class Team {
static hasMany = [players : Player]
String name;
String size;
}
Player.groovy is :
class Player {
static hasMany = [teams : Team]
static belongsTo = Team
String fullName;
String age;
}
TeamController.groovy is :
class TeamController {
def save() {
def player = new Player(fullName : "John Doe", age : "21").save()
def team = new Team(name : "LocalXI", size : "1").addToPlayers(player).save();
println "The players in the team are : " + team.players
println "The teams this player belongs to are : " + player.teams
}
}
Output for the above (when i call 'save' action ) :
The players in the team are : [John Doe]
The teams this player belongs to are : [LocalXI]
I am new to Grails and Groovy and have spent a lot of time trying to figure this out.
It should work. Take into consideration that the save method is transactional by default and it won't actually persist the data until the method is finished. Within the transaction everything looks correct, that is why the println output is correct.
If you are testing this controller via integration test, your data won't be persisted as the transaction is rolled back automatically for each test.
If you are testing this manually via browser make sure your are not using an in-memory DB in your current runtime environment.
I'm using Vaadin 7 + Grails 2.3, there is some questions
My domain classes
class Base {
private static final Date NULL_DATE = new Date(0)
Date createdAt = NULL_DATE;
Date updatedAt = NULL_DATE;
def beforeInsert(){
createdAt = new Date();
updatedAt = new Date();
}
def beforeUpdate(){
updatedAt = new Date();
}
static mapping = {
autoTimestamp true
}
}
abstract class Person extends Base{
String name;
String name2;
String phone1;
String phone2;
static constraints = {
name2 nullable:true
phone1 nullable:true
phone2 nullable:true
}
}
class Customer extends Person {
double credit;
}
THE PROBLEMS
PROBLEM 1
In my Vaadin class UI, if I try this
class MyUI extends UI {
#Override
protected void init(VaadinRequest vaadinRequest) {
Customer customer = new Customer()
customer.name="RODRIGO"
customer.save()
}
}
Show this error
Servlet.service() for servlet [VaadinServlet 0] in context with path [/AgileWeb] threw exception [com.vaadin.server.ServiceException: groovy.lang.MissingPropertyException: No such property: name for class: agileweb.Customer
Possible solutions: all] with root cause
Message: No such property: name for class: agileweb.Customer
Possible solutions: all
there is no "name" property? The class Customer extends Person that has this property.
PROBLEM 2
If I try this
Customer customer = new Customer()
Customer.setName("RODRIGO")
Customer.save()
Show thos error : Message: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
I have seach about this error but I didn't understand to fix it, maybe I'm new with Grails
PROBLEM 3 - ACTUALLY IS A QUESTION
I know that I can use BeanItemContainer, just from List object, that is possible with no problem, but BeanItemContainer is not lazy load, I'd like to use HbnContainer addon (https://vaadin.com/directory#addon/hbncontainer) becase it just need a hibernate session, so How Can I get the "Hibernante session", is there any example and how to do it?
PROBLEM 4 - ACTUALLY IS A QUESTION (AGAIN)
Following this tutorial https://vaadin.com/wiki/-/wiki/Main/Vaadin%20on%20Grails%20-%20Database%20access
It works to save object in the database, but the questions
- Is it really necessary to create a service for each domain class? I have read that it's recomend to put domain logical in the services, I agree with this, but what about simple domain that no need any logical?
so, is there possible to create something like DAO for services? is there any service design to avoid repeted code just to save objects?
I know that are many questions but I think these questions are the same of others, I really want to use Vaadin + Grails to enjoy the better of both, but is not easy to me at the moment!
Before I start answering your question, let me question you domain model. Base class is generally fine, but I want to talk about Person and Customer. You may have good reasons why you picked up inheritance, but please think of composition. Maybe you could have Person that contains a reference to an enum, that states type of the person. You could start here with that: http://en.wikipedia.org/wiki/Composition_over_inheritance
I think you have a typo there. Call save() method on 'customer' not 'Customer', which is a class
When there is a request coming to Grails application, it opens a session and the session is available during that request. There is not this kind of behavior like that in Vaadin. You need to put it into a Service. Yes, you can make generic service to save an object
class GenericService { def save(def domain) { domain.save(failOnError:true) }}
You can get the session factory like this
import org.codehaus.groovy.grails.commons.ApplicationHolder as AH
def ctx = AH.application.mainContext
def sessionFactory = ctx.sessionFactory
or
ApplicationContext applicationContext = grailsApplication.mainContext
ConfigurableLocalSessionFactoryBean factory = applicationContext.getBean('&sessionFactory')
As I wrote, you could create GenericService or a service per domain object. Just to keep in mind that GenericService should only save an object and contain no other logic that would be specific for a domain object.
How to determine Class type of Object in collection?
class Human{...}
class Man extends Human{...}
class Women extends Human{...}
def humans = Human.findAll()
humans.each(){ human ->
// ??? , it is not work
if ( human instanceof Man ) { println "Man" }
if ( human instanceof Woman ) { println "Woman" }
}
Thanks a lot,
Tom
Based on your description, I would say you are running into Hibernate proxy objects (ie. class name is: Human_$$javaassist*). Solution would be to use the GORM provided version of insatnceOf. No need to eager fetch or use a different method.
def planet = Planet.get(1)
planet.humans.each(){ human ->
if (human.instanceOf(Man)) { println "is Man"}
if (human.instanceOf(Woman)) { println "is Woman"}
}
Notice the difference human.instanceOf(Man) rather than human instanceof Man. Use the gorm method rather than the java keyword.
You can see this section of the reference documentation for an [explanation][1]. See subsection "Lazy Single-Ended Associations and Proxies"
[1]: http://grails.org/doc/latest/guide/single.html#5.5.2.8 Eager and Lazy Fetching
It looks as if it should work.
A couple random thoughts: are your humans correctly built? Maybe they are really not instances of Man or Woman.
You can do some tests using polymorphism:
class Human{ ...
def speak() { println "Human" }
}
class Man extends Human{ ...
def speak() { println "Man" }
}
class Women extends Human{ ...
def speak() { println "Woman" }
}
def humans = humanService.all()
humans.each(){ human ->
human.speak()
}
If the last line prints "Human Human Human", then the humans are not correctly built, and they are all human instances, instead of Man / Woman. If it shows an error, then they are something else (like nulls or something)
Good luck!
There's nothing wrong with the code above, so my guess is that Human.findAll() is returning an empty collection, which would explain why nothing is being printed. Can you try this code instead?
class Human{...}
class Man extends Human{...}
class Women extends Human{...}
println "You have ${Human.findAll().size()} humans"
If this prints "You have 0 humans", then my guess is correct. If you want to get a list of all instances of Human, then it's probably better to use Human.list() instead of Human.findAll()
in Grails with Hibernate is really problem with instanceof. I have again trouble with it. I find this article:
http://community.jboss.org/wiki/ProxyVisitorPattern
I mean that trouble is appear when your class has some relations.
For example:
def planet = Planet.get(1)
planet.humans.each(){ human ->
//it is not work, see the link above
if (human instanceof Man) { println "is Man"}
if (human instanceof Woman) { println "is Woman"}
}
Tom
thank for your help. I try your test. Method speak() return expected results.
For Man return "Man", for Woman return "Woman".
Your test finished ok, but my trouble is always here.
Maybe I forgot get more information:
This code is from Grails project. I mean that it is not important.
Exactly I use GORM call:
def humans = Human.findAll()
Tomas
Which version of Grails? I just tried this in the Grails 1.2.2 console and it works:
new Woman(name: "Julie").save()
new Woman(name: "Xena").save()
new Woman(name: "Mary").save()
new Man(name: "James").save()
new Man(name: "Tony").save(flush: true)
def people = Human.list()
for (p in people) {
println ">> ${p.name} (${p.getClass()})"
if (p instanceof Man) println "It's a man"
if (p instanceof Woman) println "It's a woman"
}
Perhaps it's an issue that has been fixed?
Is it possible to explicitly set the id of a domain object in Grails' Bootstrap.groovy (or anywhere, for that matter)?
I've tried the following:
new Foo(id: 1234, name: "My Foo").save()
and:
def foo = new Foo()
foo.id = 1234
foo.name = "My Foo"
foo.save()
But in both cases, when I print out the results of Foo.list() at runtime, I see that my object has been given an id of 1, or whatever the next id in the sequence is.
Edit:
This is in Grails 1.0.3, and when I'm running my application in 'dev' with the built-in HSQL database.
Edit:
chanwit has provided one good solution below. However, I was actually looking for a way to set the id without changing my domain's id generation method. This is primarily for testing: I'd like to be able to set certain things to known id values either in my test bootstrap or setUp(), but still be able to use auto_increment or a sequence in production.
Yes, with manually GORM mapping:
class Foo {
String name
static mapping = {
id generator:'assigned'
}
}
and your second snippet (not the first one) will do the job (Id won't be assigned when passing it through constructor).
What I ended up using as a workaround was to not try and retrieve objects by their id. So for the example given in the question, I changed my domain object:
class Foo {
short code /* new field */
String name
static constraints = {
code(unique: true)
name()
}
}
I then used an enum to hold all of the possible values for code (which are static), and would retrieve Foo objects by doing a Foo.findByCode() with the appropriate enum value (instead of using Foo.get() with the id like I wanted to do previously).
It's not the most elegant solution, but it worked for me.
As an alternative, assuming that you're importing data or migrating data from an existing app, for test purposes you could use local maps within the Bootstrap file. Think of it like an import.sql with benefits ;-)
Using this approach:
you wouldn't need to change your domain constraints just for
testing,
you'll have a tested migration path from existing data, and
you'll have a good data slice (or full slice) for future integration tests
Cheers!
def init = { servletContext ->
addFoos()
addBars()
}
def foosByImportId = [:]
private addFoos(){
def pattern = ~/.*\{FooID=(.*), FooCode=(.*), FooName=(.*)}/
new File("import/Foos.txt").eachLine {
def matcher = pattern.matcher(it)
if (!matcher.matches()){
return;
}
String fooId = StringUtils.trimToNull(matcher.group(1))
String fooCode = StringUtils.trimToNull(matcher.group(2))
String fooName = StringUtils.trimToNull(matcher.group(3))
def foo = Foo.findByFooName(fooName) ?: new Foo(fooCode:fooCode,fooName:fooName).save(faileOnError:true)
foosByImportId.putAt(Long.valueOf(fooId), foo) // ids could differ
}
}
private addBars(){
...
String fooId = StringUtils.trimToNull(matcher.group(5))
def foo = foosByImportId[Long.valueOf(fooId)]
...
}