Hi I don't really understand whay this doesnt work, but im 99% sure its a GORM issue.
here's my domains:
Class Product{
String name
static hasMany = [parts:Parts]
static mappedBy = [parts:'product']
}
Class Parts{
Product product
static hasMany = [alternatives:Alternatives]
}
so a Product is made up of parts and a part points to a product
When I do the following it doesn't save to the database.
Product p = new Product(name:"test")
Product part1 = Product.get(2)
Product part2 = Product.get(3)
Parts c = new Parts(product: part1).save(flush:true,failOnError:true)
Parts c2 = new Parts(product: part2).save(flush:true,failOnError:true)
p.addToParts(c)
p.addToParts(c2)
p.save(flush:true,failOnError:true)
This doesn't throw any error but also doesn't persist anything to the database.
Any Ideas?
Product p = new Product(name: "test")
Product part1 = Product.get(2)
Product part2 = Product.get(3)
p.addToParts(new Parts(product: part1))
p.addToParts(new Parts(product: part2))
p.save(flush: true, failOnError: true)
The best way to do this is to create the new Parts within your .addToParts() call.
It also seems as though you should have static belongsTo = Product within your Parts class. (Only allowing one side of the Many-to-Many relationship to persist can cause less confusion)
Related
class Client {
String name
String surname
String address
static hasMany = [departments:Department]
}
class Department {
/*static constraints = {
}*/
String depName
String location
static hasMany = [clients:Client]
static belongsTo = Client
}
def deleteDepartment(){
def values = params.list('departments')
def checkedID = new Integer[values.size()]
for(int i=0; i<values.size(); i++){
String temp = values.get(i).toString()
checkedID[i] = temp.toInteger()
}
for(int i=0; i<checkedID.length; i++){
def department = Department.get(checkedID[i])
department.clients.clear() //something
department.save() //wrong
}
}
Client has many departments. How I can delete Department domain object which has relationship with Client domain class, without deleting Client domain object?
How about this?
Department.get(id).delete()
You dont need to clear the clients because in your r/ship you dont have Client belongs to Department r/ship.
department.clients.clear() //something
This a common problem. When you create a many to many relationship
Your case will create three tables client, 'departmentandclient_department`.
Now when you try to delete the department. Hibernate tries to remove the department from department table.
This will fails because its entry is already saved in client_department table with a foreign key reference.
This should ideally first remove the mapping entry and then remove the department from tables. but this is not how it works.
So a good workaround for maintaining many to many relationships is to keep this mapping in your own hands as shown below.
Client{}
Department{}
ClinetDepartment{
Client client;
Department department;
}
This will however force you to save the objects also independently.
like
client.save();
department.save();
new ClinetDepartment(client,department).save();
while deleting you can do
clinetDepartment.delete();
department.delete();
I found solution
def department = Department.get(checkedID[i])
def tmp = []
department.clients.each {tmp << it}
tmp.each {department.removeFromClients(it)}
department.delete(flush:true)
I have the following domain classes:
class Team{
static hasMany = [localMatches: Match, visitingMatches: Match]
static mappedBy = [localMatches: 'localTeam', visitingMatches: 'visitingTeam']
List<Match> localMatches = new ArrayList<Match>()
List<Match> visitingMatches = new ArrayList<Match>()
}
class Match{
Team localTeam
Team visitingTeam
}
When I run the following:
Match match = new Match(localTeam: aLocalTeam, visitingTeam: aVisitingTeam)
match.save(flush: true, failOnError: true)
I get the exception "Caused by: org.h2.jdbc.JdbcSQLException: NULL not allowed for column "LOCAL_TEAM_ID"; SQL statement:"
So I need to set the match in each team before saving the match to avoid the exception:
Match match = new Match(localTeam: aLocalTeam, visitingTeam: aVisitingTeam)
aLocalTeam.localMatches.add(match)
aVisitingTeam.localMatches.add(match)
match.save(flush: true, failOnError: true)
Is there any way of mapping the classes so I wouldn't need to do add the match to each team before saving?
The hasMany block defines that a Match has many localMatches, but then below redefines localMatches as a relationship to a single Match. What I believe you actually mean is:
class Team {
static hasMany = [localMatches: Match, visitingMatches: Match]
static mappedBy = [localMatches: 'localTeam', visitingMatches: 'visitingTeam']
}
class Match {
Team localTeam
Team visitingTeam
}
Mapped this way, Team will have two collections of Matches and each Match will have a local and visiting Team.
During an archive process I am copying the details from an existing domain object to a new instance of that domain. Both domain objects have a hasMany relationship:
static hasMany = [pets:Pet]
When I have the following scenario:
def ownerOne = (logic to find owner)
def ownerTwo = new Owner
****ownerTwo.pets = ownerOne.pets****
How do I do that starred line? I've tired this:
Set<Pet> ownerTwoPets = new TreeSet<Pet>()
for(Pet p : ownerOne.pets) {
ownerTwoPets.add(p)
}
ownerTwo.pets = ownerTwoPets
With no luck. I can do it with String objects in a hasMany without problem. But I cannot figure it out with domain objects in a hasMany
Grails has a built in method to add to a relationship like this one. Try this:
ownerOne.pets.each { Pet p ->
ownerTwo.addToPets(p)
}
I am using Grails 1.3.6 and I am having problems getting saves to cascade properly. The problem is specifically with classes that have two parent classes. A simplified version of what I am attempting is this:
class Location {
String city
static hasMany = [authors: Author, publishers: Publisher]
}
class Author {
String name
static belongsTo = [location: Location]
static hasMany = [books: Book]
}
class Publisher {
String name
static belongsTo = [location: Location]
static hasMany = [books: Book]
}
class Book {
String title
static belongsTo = [author: Author, publisher: Publisher]
}
class Srv1Service {
static transactional = true
def loadData() {
def l1 = new Location(city: "London")
def a1 = new Author(name: "Graham Greene")
l1.addToAuthors(a1)
def p1 = new Publisher(name: "Some Press")
l1.addToPublishers(p1)
def b1 = new Book(title: "The Comedians")
a1.addToBooks(b1)
p1.addToBooks(b1)
l1.save()
}
}
If I run the above loadData, the Book instance is saved before the Publisher instance, resulting in the error "not-null property references a null or transient value: adhoc.Book.publisher".
I have tried various different ways of defining the relationships with little success. I have tried interim saves, and this does work, but I can see that parent tables are updated as I save the child data - ie Location, Author and Publisher all get updated to version 1. (And also I would like to keep the code as simple as I can.) I would like to avoid linking tables.
Any advice is gratefully received!
Okay, so the key here is that saves are cascaded from parent to children. You have a problem when it comes to Book because Book is the child to both Publisher and Author. GORM tries to save Location, Location tries to save Author, Author tries to save Book BUT the save fails because Book has a transient Publisher.
Try adding an intermediate save right before you create your Book:
def loadData() {
def l1 = new Location(city: "London")
def a1 = new Author(name: "Graham Greene")
l1.addToAuthors(a1)
def p1 = new Publisher(name: "Some Press")
l1.addToPublishers(p1)
l1.save() // add this save
def b1 = new Book(title: "The Comedians")
a1.addToBooks(b1)
p1.addToBooks(b1)
l1.save()
}
I created a local Grails project with your domain classes adding in this save. The cascading is working as you would expect.
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 {}
}
}