2016-04-06 15 views
0

Sagen, ich habe folgende (stark vereinfacht) GORM Domain-Klassen:Liste vs gesetzt, wenn eine GORM Domain Klasse Hinzufügen

class PhoneCall extends Interaction { 
    Survey survey 
} 

class Survey { 
    String campaignCode 
    Integer clientId 
    Boolean isDynamic 
    List interactions 

    static constraints = { 
     campaignCode unique: true, nullable: false 
     clientId nullable: true 
     isDynamic nullable: true 
    } 

    static hasMany = [interactions: Interaction] 
} 

class Interaction { 
    String clazz 
    Instant dateCreated 

    static constraints = { 
    } 

    static mapping = { 
     tablePerHierarchy false 
     autoTimestamp false 
    } 

    def beforeInsert() { 
     dateCreated = Instant.now() 
    } 
} 

Ich habe den folgenden einfachen Code diese Klassen für einen Test einzurichten:

def survey = new Survey(campaignCode: "TEST", isDynamic: true).save(failOnError: true, flush: true) 
def phoneCall = new PhoneCall(survey: survey, clazz: PhoneCall.name).save(failOnError: true) 

Dieser schlägt mit dem folgenden Stack-Trace:

org.springframework.dao.DataIntegrityViolationException: could not insert: [uk.co.nttfundraising.onitfhi.domain.PhoneCall]; SQL [insert into phone_call (id) values (?)]; constraint [survey_id]; nested exception is org.hibernate.exception.ConstraintViolationException: could not insert: [uk.co.nttfundraising.onitfhi.domain.PhoneCall] 
    at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:643) 
    at org.springframework.orm.hibernate3.HibernateAccessor.convertHibernateAccessException(HibernateAccessor.java:412) 
    at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:412) 
    at org.springframework.orm.hibernate3.HibernateTemplate.execute(HibernateTemplate.java:339) 
    at org.codehaus.groovy.grails.orm.hibernate.metaclass.SavePersistentMethod.performSave(SavePersistentMethod.java:56) 
    at org.codehaus.groovy.grails.orm.hibernate.metaclass.AbstractSavePersistentMethod.doInvokeInternal(AbstractSavePersistentMethod.java:215) 
    at org.codehaus.groovy.grails.orm.hibernate.metaclass.AbstractDynamicPersistentMethod.invoke(AbstractDynamicPersistentMethod.java:63) 
    at org.codehaus.groovy.grails.orm.hibernate.HibernateGormInstanceApi.save(HibernateGormInstanceApi.groovy:196) 

Allerdings, wenn ich die Zeile entfernen List interactions von Survey (machen interactions in eine Set), alles funktioniert gut. Es gibt auch keine Probleme, wenn ich SortedSet interactions verwende, obwohl das generierte Datenbankschema anscheinend keine Reihenfolge hat, also bin ich mir nicht sicher über diese Lösung. Google schlägt meistens vor, die Survey (z. B. this blog post) nicht zu speichern, aber ich habe dies vergeblich versucht.

Es ist nur die List, die fehlschlägt, und es verursacht die Einfügung in PhoneCall, meine Survey vollständig zu ignorieren! Was ist los?

Antwort

1

Ein Vorbehalt bei der Verwendung eines List ist, dass das Element, das Sie hinzufügen, nicht save() d vor dem Hinzufügen zu List sein kann. Aber noch wichtiger ist, dass die richtige Methode zum Hinzufügen von Elementen zu einer Sammlung bei Verwendung einer Eins-zu-viele-Verknüpfung survey.addToInteractions() ist, siehe addTo*(). Aber zuerst müssen Sie eine richtige Vereinigung ...

class PhoneCall extends Interaction { 
    static belongsTo = [survey: Survey] 
} 

Durch das Ersetzen der Survey Eigenschaft mit belongsTo, erhalten Sie eine richtige bi-directional one-to-many association. Dann können Sie/testen Sie es wie folgt aus:

def survey = new Survey(campaignCode: "TEST", isDynamic: true) 

survey.addToInteractions(new PhoneCall(survey: survey, clazz: PhoneCall.name)) 
survey.save(failOnError: true, flush: true) 

Beachten Sie, dass die PhoneCall wird nie explizit gespeichert, und PhoneCall.survey nicht explizit zugeordnet. All dies wird erledigt, wenn survey.save() aufgerufen wird.

Nach dem Speichern wird someSurvey.interactions[index].survey auf die someSurvey verweisen.