How to create valid Domain objects at runtime in Grails
I have a few domain classes, and I want to be able to populate a new Domain class and persist it to the database via one of my controllers. Here are my classes
class Employee implements Comparable
{
static hasMany = [education:Education]
static mapping = {
education cascade:"all,delete-orphan", lazy:false
}
List<Education> education = new ArrayList<Education>();
}
public class Education implements Comparable
{
static belongsTo = [employee:Employee]
String collegeName
String areaOfStudy
String yearGranted
Date lastModified
Boolean inProcess = false;
EducationType type = new EducationType(name:"None");
}
class EducationType
{
String name="";
}
Now I want to create a new Education entry for a particular employee from this controller.
def employee = Employee.get(session.empid);
EducationType et = new EducationType(name:'JD')
Education ed1 = new Education(collegeName:'Harvard1', areaOfStudy:'Law', yearGranted:'2015', type:et, lastModified:new Date(), employee:employee)
employee.addToEducation(ed1)
employee.save()
For some reason this is not behaving as expected and I get this exception:
2010-09-24 10:56:01,503 [http-8080-1] ERROR errors.GrailsExceptionResolver - not-null property references a null or transient value: Education.type; nested exc
eption is org.hibernate.PropertyValueException: not-null property references a null or transient value: Education.type
org.springframework.dao.DataIntegrityViolationException: not-null property references a null or tr开发者_StackOverflow社区ansient value: Education.type; nested exception is org.hiberna
te.PropertyValueException: not-null property references a null or transient value: Education.type
at org.jsecurity.web.servlet.JSecurityFilter.doFilterInternal(JSecurityFilter.java:382)
at org.jsecurity.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:180)
at java.lang.Thread.run(Thread.java:619)
Caused by: org.hibernate.PropertyValueException: not-null property references a null or transient value: Education.type
... 3 more
I can get this to go away by first saving the EducationType with an et.save() and then saving the Education object with ed.save() and finally saving the employee.
Why is this necessary? Doesnt my mapping say that a save on employee should trickle down to any non-persisted objects that are now associated with the employee?
Also - why do I have to explicitly add employee when I initalize the Education object? It is specified in the belongsTo object, and it seems like when I do the employee.addToEducation() call it should be picked up automatically, right?
Thanks!
Your Education to EducationType is defined as a simple one-to-one. To cascade from Education to EducationType, I think you can make the latter belongTo the former. Check out 5.2.1.1 of the user guide. Note you have to be careful of what persistence semantics you want? Do you really want EducationTypes to be their own entities?
I think you have to add the employee to Education because you have a bidirectional one to many. Both sides of the relationship have to be set up. addToEducation works to add to the owning side of the relationship a member of the collection. Evidently, It does not set the relationship from the owned side to the owning side.
---- edit ----
I just looked at the docs because your second error seems wierd
"The addTo* method is a dynamic method that uses an association to automatically add instances to the association. It also automatically configures bi-directional relationship so that both sides o the relationship have been set."
So it seems that addTo should be setting both sides of the relationship...If you take the employee: employee out of your Education creation it does not work?
精彩评论