I have there domain classes:
Person. (Person.ID, Name,Address)
Designation.(Designation.ID, Title, Band)
SalarySlip (Person.ID, Designation.ID, totalIncome, Tax etc etc.)
In the update method the person controller when I assign a person a designation from a list of designation values I want to insert a new record inside SalarySlip.
Something like:
def update = {
def SalarySlipInstance = new SalarySlip()
SalarySlipInstance.Person.ID = Params.ID //is this correct?
SalarySlipInstance.Designation.ID = ?? //since the value is coming from a list. How can I bind this field?
}
You need to load the Person and Designation objects first:
salarySlipInstance.Person = Person.get(params.person.id)
salarySlipInstance.Designation = Designation.get(params.designation.id)
If in your form you prefix the person and designation id's with person. and designation. it makes it easier to load.
Related
I have tow domain
class Book {
String name
Long id
}
class BookRef {
String name
Long id
String refId
}
In Book table, I stored data like id=1, name='Java'.
Now I can initiate BookRef by getting Book like bellow
def book = Book.get(1)
def bookref = new BookRef()
bookref.id = book.id
bookref.name = book.name
bookref.refId = '1'
bookref.save()
But I want to initiate the bookref object by using the book object like params binding not by binding each individual properties.
For now, I have now used the property to property initialization but in a domain with various properties, it's time-consuming.
How can I do this?
Here you go:
Book book = Book.get(1)
// Option 1
BookRef bookref = new BookRef(book.properties)
bookref.refId = '1'
bookref.save()
// Option 2
BookRef bookref = new BookRef()
bookref.properties = book.properties
bookref.refId = '1'
bookref.save()
Basically, in Grails, any domainInstance.properties gives you a map of all the domain fields.
Please note, this approach is good for primitive types like String, boolean, int, Long etc but Grails might throw an exception when the domain has collections, one-to-many or has-many relationship fields.
I have an app with the following entities:
Topic:
class Topic {
UUID id
String description
String name
boolean visibility = true
// Relation
static hasMany = [tests:Test]
...
}
Test:
class Test {
UUID id
boolean active = true
String description
...
static hasMany = [evaluationsTest: Evaluation]
static belongsTo = [topic: Topic, catalog: Catalog]
}
When I show all visible topics to the user I request the query:
def visibleTopics = Topic.findAllByVisibility(true, [sort:"name", order:"asc"])
This query returns me for example: [['English'], ['Spanish']]. Then, I can show the full information about each topic to the user.
But I also want to indicate to the user the number of active test in each visible topic.
For example:
English topic has 2 active test.
Spanish topic has a total of 2 test. One is active and the other is not.
German topic has not any active test.
Then I need a query whose result is: def activeTotalEachTopic = [[2],[1],[0]] and I can pass the activeTotalEachTopic variable to the view (.gsp).
Solution:
From the first query where I can obtain all visible topics, I get the number of active test.
def visibleTopics = Topic.findAllByVisibility(true, [sort:"name", order:"asc"])
def numberActiveTest = []
activeTopics.each { topic ->
def result = Test.findAllByTopicAndActive(topic, true).size()
numberActiveTest.push(result)
}
And I pass to the view both variables.
render view: 'home', model: [activeTopics: activeTopics, numberActiveTest: numberActiveTest]
What you are missing is grouping so that you get the count per group, rather than a total count.
You also need to change the join type from the default inner join to an outer join in order for topics without an active test to return 0. However, a side-effect of this is that it changes how association properties are referenced due to the alias that's created by the join. Something like this:
import static org.hibernate.sql.JoinType.*
def activeTotalEachTopic = Topic.createCriteria().list() {
createAlias('tests', 't', LEFT_OUTER_JOIN)
eq 'visibility', true
or {
eq 't.active', true
isNull 't.id'
}
projections {
groupProperty 'name'
count()
}
order ("name", "asc")
}
Now, another issue to address is that the output would be something like this due to the grouping: [['English', 2],['Spanish', 1],['German', 0]]. So what you can do is collect the second item in each sub-list:
activeTotalEachTopic*.getAt(1)
// Which is the equivalent of...
activeTotalEachTopic.collect { it[1] }
Objective:
Return a composite response from my query, containing columns from both related models using Eloquent so that I can use Form::model to restore field values for User values AND Addresses values in my view. I want all the data in a single object and I don't want to use compact or otherwise manipulate the data if I don't have to.
Tables:
users (id, userWorkAddressID, ...)
addresses (ID, ...)
Models
User
public function address()
{
return $this->hasOne('Address', 'ID', 'userWorkAddressID');
}
Address
public function user()
{
return $this->belongsTo('User', 'id', 'userWorkAddressID');
}
Things I've tried
$user = User::find($id);
This just returns user data - no address data
$user = User::find($id)->address
This just returns the address for the user, but no user data
$user = User::with('address')->find($id);
This returns the user data, no address data
$user = User::with(array('address' => function($query){
$query->addSelect(array('id', 'addressLine1'));
}))->find($id);
This also returns only the user data, no address data
I could just use Fluent, but do I have to?
How can I use Eloquent to join those two tables and return a single object consisting of the fields I represent in my view?
First off your relations are wrong. Change both to:
public function address()
{
return $this->hasOne('Address', 'userWorkAddressID', 'ID');
}
Address
public function user()
{
return $this->belongsTo('User', 'userWorkAddressID', 'id');
}
then probably you will see the related model. Just remember to:
1 Eager load the related model: `$user = User::with('address')->find($someId);
2 use array notation for related model properties in the form: Form::model($user, ..) Form::text('address[city]', ...)
I am using Grails 2.2.4 and having one Domain contains value as map and I want to find domain object using key of map. Please help me to resolve this issue.
Student.groovy
package com.grails
import java.util.Map;
class Student {
String firstName
String lastName
Map address
static constraints = {
}
}
When My application are run I can see that Grails application create tables in database are as follow:
1) first table
student
id
version
first_name
last_name
indexes
2) second table
student_address
address
addres_idx
addres_elt
When I save Domain as:
def std = new Student()
std.firstName = 'Piyush'
std.lastName = 'Chaudhari'
std.address = [city:'Surat',state:'Gujarat',pincode:'38001']
std.save(flash:true)
values are insert in database as follow:
student table
ID VERSION FIRST_NAME LAST_NAME
1 0 Piyush Chaudhari
student_address table
ADDRESS ADDRESS_IDX ADDRESS_ELT
1 city Surat
1 state Gujarat
1 pincode 38001
Now, I want data or row using GORM like Student.findBy_____ or Student.findAllBy______
where 'city' = surat
Any one can help me to resolved this issue?
You can use:
Student.findBy<FieldName1>And<FieldName2> (<FieldNameParameter1>, <FieldNameParameter2>)
Or Either:`
Student.list().find { it.address.city == 'Surat' }
Student.list().findAll { it.address.city == 'Surat' }
`
I don't think that you can search things like this using maps.
Maybe you can do this:
def students = Student.list()
def result = students.each { student -> student.address.city == 'Surat' }
println("Resultado" + result)
But this is a very bad way to do this kind of things
Define an address class, and then add an address field to the student class (this will change how your tables are mapped in the database):
class Student {
String firstName
String lastName
Address address
static constraints = {
}
}
class Address {
String city
String state
String pincode
}
Address should be another entity in your domain, not a map of values. Remember that Grails GROM is an ORM, so you should design your domain using a OOP model in order to take advantage of the dynamic finders and criterias for doing queries.
With those changes in place, you can now use a simple criteria:
def students = Student.withCriteria{
'address'{
eq('city', 'surat')
}
}
More information about criterias in the grails docs:
http://grails.org/doc/latest/ref/Domain%20Classes/withCriteria.html
http://grails.org/doc/latest/guide/single.html#criteria
If you want to use Dynamic finders, you will have to get all the address with city = 'surat' and then use a findByAddressInList(...). But i think that in this case, criterias is a better approach
Maybe a silly question but where/how should I define default values for GORM domain class properties? For example when I'm creating a new Company object instance I want default value for property country to be "USA". I guess I could do it in create controller but it looks kinda dirty. Something like:
def create = {
def companyInstance = new Company()
companyInstance.properties = params
companyInstance.accepted = "USA"
...
Put it in the domain class itself
class Company {
String country = "USA"
}