| 

.NET C# Java Javascript Exception

Abfrageproblem

Dies ist das Archiv des ehemaligen Forums zum Thema Groovy, Grails, Griffon und Bean Scripting Framework, welches unter groovy-forum.de existierte. Die neue Adresse des Groovy-Forums ist: http://codekicker.de/fragen/themen/groovy.


Abfrageproblem

helgoboss - 07.05.2008 12:08
Hallo!

Vielleicht könnt ihr mir ja bei folgendem Problem helfen.

Es gibt diese Domänenklassen:

class Contact {
    
    static hasMany = [versions: ContactVersion]

    ContactVersion getLatestVersion() {
        if(versions?.size() > 0) {
	    return versions.max()
        } else {
	    return null
	}
    }
   
    // Nötig um zu Verhindern, dass GORM die Referenz zur aktuellten Version persistent macht.
    static transients = ["latestVersion"]

}

class ContactVersion {
    
    static belongsTo = [contact: Contact]

    // Versionsnummer
    int number 

    // Versionierte Kontaktdaten
    String name
    String city
    ...
}

Der Hintergrund: Versionierbare Kontaktdaten. Verändert ein Benutzer die Daten eines Kontakts, wird ein neues ContactVersion-Objekt angelegt und dem Contact-Objekt hinzugefügt. Über die Methode Contact.getLatestVersion() lässt sich zu einem Kontakt leicht die aktuelle Version abrufen. Die Referenz auf die aktuelle Version muss nicht persistent sein da die aktuelle Version eines Kontakts implizit klar ist (die Kontaktversion mit der größten Versionsnummer). Soweit klappt es mit dieser Modellierung. Will man alle Kontakte mit den jeweiligen Daten in der aktuellen Version ausgeben, kann man so vorgehen:

Contact.findAll().each{
    println "${it.id}, ${it.latestVersion.name}, ${it.latestVersion.city}"
}

Jetzt zum eigentlichen Problem. Ich möchte eine Hibernate-Abfrage machen, die mir Kontakte zurückliefert, deren aktuelle Version bestimmte Bedingungen erfüllt. Beispielsweise: Gebe mir alle Kontakte, die aktuell in der Stadt Dresden wohnen.

Ideen:

1.)
Contact.findAll().each{
    if(it.latestVersion.city == "Dresden") {
        println "${it.id}, ${it.latestVersion.name}, ${it.latestVersion.city}"
    }
}

Natchteil: Keine reine Hibernate-Abfrage, Hibernate gibt erstmal alle Kontakte zurück und danach werden sie mit Groovy-Code gefiltert, es werden viele Objekte erzeugt, deswegen evtl. Performance-Probleme

2.)
Eine etwas kompliziertere HQL-Abfrage bauen, die Kontakte mit ihrer aktuellen Version "joint" und in der WHERE-Klausel
latestVersion.city = "Dresden"
stehen hat. Da müsste man wahrscheinlich mit GROUP BY und MAX() arbeiten, womit wir auch beim Thema Datenbankkompatibilität wären.

Nachteil: Kompliziertere Abfrage, Performance-Probleme?

3.)
latestVersion-Property persistent machen (Redundanz). Dann sieht die Hibernate-Abfrage sehr einfach aus und die Performance wird kein Problem sein.

Nachteil: Habe das ausprobiert, aber seit Grails 1.02 macht da GORM nicht mehr mit. Wahrscheinlich kommt es nicht damit zurecht, dass ContactVersion zu Contact gehört (belongsTo) und Contact zwei Arten von persistenten Beziehungen zu ContactVersion pflegt (hasMany UND "hasOne").

4.)
Die Modellierung verändern.

Nachteil: Man muss die Modellierung verändern :)


Wie würdet ihr die Sache angehen?

Viele Grüße
Benjamin


Re: Abfrageproblem

helgoboss - 07.05.2008 15:15
Hallo Christian!

Habe gerade mal versucht, Lösung 3 (redundant persistente latestVersion-Referenz) zu implementieren aber die mappedBy-Property hilft leider nicht dabei, den Fehler zu beseitigen.

class Contact {
    
    static hasMany = [versions: ContactVersion]
    static mappedBy = [versions: "contact", latestVersion: "latestVersionContact"]

    ContactVersion latestVersion
   
}

class ContactVersion {
    
    static belongsTo = [contact: Contact, latestVersionContact: Contact]

    // Versionsnummer
    int number 

    // Versionierte Kontaktdaten
    String name
    String city
    ...
}

Die Fehlermeldung ist:

org.codehaus.groovy.runtime.InvokerInvocationException: org.springframework.dao.
DataIntegrityViolationException: not-null property references a null or transien
t value: de.mms_dresden.mpanalyse.core.ContactVersion.contact; nested exception
is org.hibernate.PropertyValueException: not-null property references a null or
transient value: de.mms_dresden.mpanalyse.core.ContactVersion.contact

Und das, obwohl ich die Referenzen beidseitig gesetzt habe:

contact.versions << newVersion
newVersion.contact = contact
contact.latestVersion = newVersion
newVersion.latestVersionContact = this

Habe es auch mit contact.addToVersions() versucht. Außerdem habe ich versucht, latestVersion nur einseitig zu definieren (sodass ContactVersion nicht noch ein belongsTo Contact hat). Ging auch nicht. Vielleicht liegt es daran, dass die eine Beziehung hasMany und die andere hasOne ist. Auf [grails.codehaus.org] wird mappedBy nur mit zwei hasMany-Beziehungen verwendet.

Dann werde ich wahrscheinlich doch zu Lösung 2 greifen.

Grüße
Benjamin


Stelle deine Groovy-Frage jetzt!


Diese Seite zeigt den Thread "Abfrageproblem" der ehemaligen Webseite groovy-forum.de, welche durch einen Serverunfall zerstört wurde. codekicker.de hat viele Konversationen über die beliebte Programmiersprache Groovy und zugehörige Frameworks wie das Grails-Framework retten können.

Hast Du eine Frage zum Thema Groovy, Grails oder allgemein Java? Viele ehemalige groovy-forum.de Mitglieder beantworten dir auf codekicker.de deine Frage! Stelle jetzt eine Frage!

Viele weitere Diskussionen zu Grails und Groovy befinden sich auf der Threadübersicht des alten groovy-forum.de.