how to add object in hasMany element - grails

I have two domain class
class Company{
String name
....
static hasMany[product:product]
}
class Product{
String Pname
String Qty
}
i am tring to add product like this
Company comp= Company.get(1)
Product pdct = Product.findByPname("procut1");///procunt name is unique
comp.product.add(pdct)
comp.save(flush:true)
the above statement are successfully executed
but when i try to find comp.product i got a empty list like []
i also try addTo but this give exception
so what m i missing?

You should be using the GORM methods for addTo and removeFrom when adding and removing members of your collection.
comp.product.add(pdct)
should be:
comp.addToProduct(pdct)

Change this as static hasMany[products:Product]
Company comp= Company.get(1)
Product pdct = Product.findByPname("procut1");///procunt name is unique
comp.addToProducts(pdct)
comp.save(flush:true)
Also add static belongsTo = [company:Company] in your Product class to apply Cascade operations

Related

Grails does not fill in foreign-key field for one-to-many relation

I'm new to grails and must be missing something important in trying to define a one-to-many mapping without using a join-table.
I have a domain object Foo
class Foo {
static hasMany = [remarks: ChangeRemark]
static mapping = {
remarks column:'PART_REMARKS_ID', joinTable:false
}
}
and another domain object ChangeRemark
class ChangeRemark {
String remark
String name
}
I initialize a Foo object, and add two ChangeRemark objects to it as such
ChangeRemark remark = new ChangeRemark(remark:"test", name:"t").save(flush:true)
ChangeRemark remark2 = new ChangeRemark(remark:"test2", name:"y").save(flush:true)
Foo foo = new Foo().save(flush:true)
foo.addToRemarks(remark).save(flush:true)
foo.addToRemarks(remark2).save(flush:true)
When I print out the size of the remarks on foo it is indeed 2, however the database column for the foreign key PART_REMARKS_ID on the ChangeRemarks table is empty. This means after I restart my application the connection between the object and the remarks can't be made
What am I missing to have grails insert the Foo id in the table.
To avoid the join table use belongsTo to create a reference from ChangeRemark to Foo.
class Foo {
static hasMany = [remarks: ChangeRemark]
}
class ChangeRemark {
String remark
String name
static belongsTo = [foo: Foo]
}
When you do this, the change_remark table gets a foo_id foreign key. This means a ChangeRemark instance can reference only a single Foo instance; which I'm assuming is your intention.
This changes how you add ChangeRemarks:
ChangeRemark remark = new ChangeRemark(remark:"test", name:"t")
ChangeRemark remark2 = new ChangeRemark(remark:"test2", name:"y")
Foo foo = new Foo()
foo.addToRemarks(remark)
foo.addToRemarks(remark2)
foo.save(flush: true)
Basically, Foo is responsible for persisting itself and the ChangeRemarks.

Unwanted GORM table creation

I have two domain classes, Person and Workshop. A Workshop has an owner of type Person, and many participants of type Person. A Person can be the participant of many workshops. When enrolling people in workshops I want to do so from the Workshop side like workshop.AddToParticipants() so here is how I set up my domain classes.
class Person {
String name
static hasMany = [enrolledWorkshops: Workshop]
static belongsTo = [Workshop]
}
class Workshop {
Date startDate
Date endDate
String name
Person owner
static hasMany = [participants: Person]
}
GORM correctly creates a WORKSHOP_PARTICIPANTS table with WORKSHOP_ID and PERSON_ID columns, and adds an OWNER_ID column to the WORKSHOP table. This is all good.
However, it ALSO creates a WORKSHOP_OWNER table with PERSON_ID and OWNER_ID columns! This makes no sense to me, and no matter how I try changing the GORM relationships I just can't get it to work how I want without this annoying extra table being created. How can I prevent the WORKSHOP_OWNER table from being created? Any help is greatly appreciated! (if it is of any help, I am using Grails 2.3.7)
In order to get rid of the WORKSHOP_OWNER table you'd have to replace Person owner with static belongsTo = [owner: Person] in the Workshop class. But that would conflict with static belongsTo = [Workshop] in the Person class. Both can't be owners.
Try this:
class Person {
String name
}
class Workshop {
Date startDate
Date endDate
String name
static belongsTo = [owner: Person]
static hasMany = [participants: Participant]
}
class Participant {
person person
static belongsTo = [workshop: Workshop]
}
In the above example, a Person owns a Workshop, and a Participant is owned by a Workshop. The workshop table will get a owner_id to refer to the person, which gets rid of the workshop_owner table.
To add a Person to a Workshop you simply wrap it in a Participant
workshop.addToParticipants(new Participant(person: somePerson))
You'd loose the enrolledWorkshops property in Person, but you can accomplish the same thing with a query.
def workshops = Workshop.withCriteria {
participants {
eq 'person', somePerson
}
}

Grails HasMany on Long

I have an class with an hasMany on a Long:
class Test {
static hasMany = [longList:Long]
}
I want to filter on longList with Criteria:
Test.createCriteria().list{
'in'('longList',[Long.valueOf('1')])
}
I get an SQLException: No value specified for parameter 1.
The SQL looks like this:
select * from test this_ where this_.id in (?)
i tried things like:
createAlias('labours', 'l')
eq('l',Long.valueOf(filter.labourId)) )
or
eq('labours.value', Long.valueOf(filter.labourId))
But i can't get it working.
For a workaround i would make another domain Class:
class Test {
statis hasMany=[longList:TestLongList]
}
class TestLongList{
Long longListItem
static belongsto = [test:Test]
}
This should be working but i must always create an TestLongList Instance if I create an Test Object, so the code would turn from:
test.addToLongList(Long.valueOf('22'))
to
TestLongList tll = new TestLongList
tll.test= test
tll.longListitem = Long.valueOf('22')
tll.save()
test.addToLongList(tll)
Is there a way to stay with the Long-List without HQL?
You have to rewrite the criteria to look like this:
Test.createCriteria().list{
createAlias('longList', 'l')
'in' ('l.elements', [1L])
}
This boils down to the property name under which Hibernate stores collection (elements).

Questions about implementing Domain class relationships & constraints in Grails

Using ArgoUML, I very quickly created this trivial representation of a few Domain classes (Person, Store, Product) and their relationships.
I'm struggling with the implementation of the relationships. Below was my initial approach for the Person domain, but it seems that I am missing something important.
class PersonToPerson {
Person from
Person to
String relation
static constraints = {
relation(inList:["Friend to", "Enemy of", "Likes", "Hates"])
}
static belongsTo = [ Person ]
}
class Person {
String firstName
String secondName
.
.
.
static hasMany= [ personToPerson:PersonToPerson,
personToStore:PersonToStore ]
}
Edit: updated question for clarity
After thinking on the problem I think I have a better way to ask the question(s). In the implementation of PersonToPerson above I have the relation as a simple string. I want the user to be able to select from a list of unique relations, which are defined in the constraints, for the string value for PersonToPerson. So this leads to the questions...
Should personToPerson and personToStore be consolidated into one list of type Relationship? Or should they stay independent lists as shown?
What is the mechanism to allow the user to add new values to the relation constraint?
1) Domain model
Keep your code simple. Don't create generic data model. It's way to hell. When you personToPerson and personToStore keep separate, it's much easier to follow your code.
Actually suggested solution makes it possible to access relations as consolidated and independent list simultaneously.
For this problem I would use inheritance feature in GORM.
Your classes would look like this:
class Person {
String name
static hasMany = [personToPerson:PersonToPerson,
personToProduct:PersonToProduct,
personToStore:PersonToStore]
static mappedBy = [personToPerson:"from"]
}
class Product{
String productName
}
class Relationship{
String note
}
class Store{
String storeName
}
class PersonToPerson extends Relationship{
Person from
Person to
String relation
static constraints = {
relation(inList:["Friend to", "Enemy of", "Likes", "Hates"])
}
static belongsTo = [ from:Person ]
}
class PersonToProduct extends Relationship{
Person person
Product product
String relation
static constraints = {
relation(inList:["likes", "dislikes"])
}
static belongsTo = [ person:Person ]
}
class PersonToStore extends Relationship{
Person person
Store store
String relation
static constraints = {
relation(inList:["Stock person", "Owner", "Manager", "Patron"])
}
static belongsTo = [ person:Person ]
}
DB schema for Person, Product and Store is usual. But for Relational domains look like this:
Relationship
Field Type Null Default
id bigint(20) No
version bigint(20) No
note varchar(255) No
class varchar(255) No
person_id bigint(20) Yes NULL
product_id bigint(20) Yes NULL
relation varchar(8) Yes NULL
from_id bigint(20) Yes NULL
to_id bigint(20) Yes NULL
store_id bigint(20) Yes NULL
Relationship domain makes possible to access all relational domain throw one domain.
2) Constraint
Just switch inList to validator. Than you can store constrain in file or DB.
See documentation or file example.
Example how to store constraint values in DB. First create a domain object.
class Constrain{
String name
String type
}
Than the domain class looks:
class PersonToPerson extends Relationship{
Person from
Person to
String relation
static constraints = {
relation(nullable:false, validator:{val, obj ->
def list = Constrain.findAllByType('person').collect{it.name}
return list.contains(val)
})
}
static belongsTo = [ from:Person ]
}
Look fine. You may want to consider a belongsTo in the PersonToPerson class.
Also, your has many in Person should be: [ personToPersons:PersonToPerson.... <- remove the s

Grails GORM Domain class relationship

Grails 1.1.1
Goovy 1.5.7
In a relationship such this:
Author 1 -- n Book n -- 1 Publisher
Defined in Grails:
class Author {
String firstName
String lastName
static hasMany = [books: Book]
static constraints = {
books(nullable: true)
}
}
class Book {
String title
Author author
Publisher publisher
static constraints = {
author(nullable: true)
publisher(nullable: true)
}
}
class Publisher {
String name
static hasMany = [books: Book]
static constraints = {
books(nullable: true)
}
}
I want to load a Book with the values of Publisher and Author.
When i get a Book with the query:
def book2 = Book.findAllByAuthor(author)
I get the response with the autor assosiated but the publisher only have the id and name class in the other query:
def book3 = Book.findAllByPublisher(publisher)
I retrieve me the inverse result,i have the book with the publisher data but the author only have the id and the class name.
Where is the error in the defined model ? o there is an error in the way to do the queries ?
Edit:
I need the way to retrieve the values only with the query like this:
def book2 = Book.findAllByAuthor(author, [fetch:[publisher:'eager']])
In this one I can manage the value of publisher.
Question: If publisher had a hasmany or Domain related, getting the book I'm able to read the attributes?
Thanks.
Thanks.
Lazy fetching is used by default with gorm associations. If you want to enable eager fetching, you can modify the ORM DSL by adding the following mappings block to your Author domain class:
static mapping = {
books lazy:false
}
or you could change the fetch mode in the domain object by adding following code after your books relationship is defined.
static fetchMode = [books:"eager"]
Doing the same to your Publisher domain object should allow you to accomplish what you want. You do want to be careful of the consequence that you may load more data than you intend to.
Shouldn't the get() method return what you are looking for?
Example: def book2 = Book.get(author)
You'd better use Criteria and explicitly define which relations should be loaded eagerly. Just mention relation in the query.
Example:
def c = Teacher.createCriteria()
List<Teacher> results = c.list {
subjects {
attendees {}
}
}

Resources