I've got two domain classes: Car and Driver. I'd like to make a gsp view that displays the Car and Driver info in a list that looks more or less a default scaffolded list. For example:
Make Model Driver Age
------------------------
Chevy Nova Joe 20
Chevy Nova Mike 30
Chevy Nova Sally 40
Here's the domain classes:
class Car {
String make
String model
static constraints = { }
static hasMany = [ drivers : Driver ]
static mapping = {
drivers joinTable: [name: 'Car_Driver', column: 'DRIVER_ID', key: 'CAR_ID']
}
}
class Driver {
String name
int age
static constraints = { }
}
Make a car and give it a few drivers:
def car = new Car(make: 'Chevy', model: 'Nova')
def driver1 = new Driver(name: 'Joe', age: 20)
def driver2 = new Driver(name: 'Mike', age: 30)
def driver3 = new Driver(name: 'Sally', age: 40)
car.addToDrivers(driver1)
car.addToDrivers(driver2)
car.addToDrivers(driver3)
car.save()
What do I need to do in my CarController and/or gsp view to make a joined list happen (and still work with pagination)?
If a Driver can have only one Car, you need a Driver to reference Car and just to render scaffolding list for a Driver.
To tweak list columns, you'll have to grails generate-views.
If a Driver can have many Cars, and you don't want to pull Car_Driver table into visible domain model (it has no own domain meaning), make a scaffolding-like list action using SQL query result as a cardriverInstancesList. Like here: SQL/Database Views in Grails.
Just check that result is a PagedResultList. If not, you can create a PagedResultList by hand, it is easily constructed from a List and totalCount, which you can find with SQL.
Related
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 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).
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.
I am using an older version of grails (1.1.1) and I am working on a legacy application for a government client.
Here is my question (in psuedo form):
I have a domain that is a Book. It has a sub domain of type Author associated with it (1:many relationship). The Author domain has a firstName and lastName field.
def c = Book.createCriteria()
def booklist = c.listDistinct {
author {
order('lastName', 'asc')
order('firstName', 'asc')
}
}
Let's say I have a list of fields I want to use for an excel export later. This list has both the author domain call and the title of the column I want to use.
Map fields = ['author.lastName' : 'Last Name', 'author.firstName', 'First Name']
How can I dynamically call the following code--
booklist.eachWithIndex(){
key, value ->
println key.fields
}
The intent is that I can create my Map of fields and use a loop to display all data quickly without having to type all of the fields by hand.
Note - The period in the string 'author.lastName' throws an error when trying to output key['author.lastName'] too.
I don't recall the version of Groovy that came with Grails 1.1, but there are a number of language constructs to do things like this. If it's an old version, some things may not be available - so your mileage may vary.
Map keys can be referenced with quotes strings, e.g.
def map = [:]
map."person.name" = "Bob"
The above will have a key of person.name in the map.
Maps can contain anything, including mixed types in Groovy - so you really just need to work around string escapes or other special cases if you are using more complex keys.
You can also use a GString in the above
def map = [:]
def prop = "person.name"
map."${prop}" = "Bob"
You can also get a map of property/value off of a class dynamically by the properties field on it. E.g.:
class Person { String name;String location; }
def bob = new Person(name:'Bob', location:'The City')
def properties = bob.properties
properties.each { println it }
why the following Groovy snippet returns alternating
[Account: 2222 and 2222, Account: 1111 and 1111] or
[Account: 1111 and 1111, Account: 2222 and 2222]
if you run it multiple times within the Groovy Console ?
I thought the sort statement leads to an ALWAYS descending sort order of the list ???
class Account {
long number
String code
String toString() {return "Account: $number and $code"}
static mapping = {
sort number:"desc"
}
}
List items = []
items << new Account(number:1111,code:'1111')
items << new Account(number:2222,code:'2222')
println items.sort()
Thanks in advance
Dominik
You don't define an ordering among your Account instances. The mapping directive is only applicable to GORM mapped classes (IOW: "domain objects"), and will only be used when loading instances of your class from the database AFAIK.
However, you are appending the objects to a plain List, which does not know about GORM properties. In order to sort lists of Account instances reliably in such a context, you will have to specify an explicit ordering, for example:
class Account implements Comparable {
...
def int compareTo(rhs) {
long onum = rhs.number;
return (onum > number)? -1 : ((onum < number)? 1 : 0);
}
...
}
This article has more information about the topic. As to why Groovy sorts the list differently on multiple calls to list.sort: well, I have no idea...
Grails has two main default ways to sort:
Sort when you query:
def airports = Airport.list(sort:'name')
Put a default sorting method on that object:
class Airport {
…
static mapping = {
sort name:"desc"
}
}
The above is taken from the grails documentation.