2012-07-14 7 views
5

Ich habe ein Problem, bei dem meine Domain-Klasse zwei potentiell einander ausschließende externe Schlüssel hat, entweder eine Seriennummer oder einen Legacy-Lookup-Wert.Wie erstelle ich eine XOR-Validierung für zwei Felder in einer Grails-Domänenklasse?

Da ich nicht sicher bin, welche ich für einen bestimmten Eintrag haben werde, habe ich sie beide Nullable und benutzerdefinierte Validierung hinzugefügt, um sicherzustellen, dass ich einen einzigen Wert habe.

package myproject 

class Sample { 

    String information 
    String legacyLookup 
    String serialNumber 

    static constraints = { 
     information(nullable: true) 
     legacyLookup(nullable: true) 
     serialNumber(nullable: true) 

     legacyLookup validator: { 
      return ((serialNumber != null && legacyLookup == null) || (serialNumber == null && legacyLookup != null)) 
     } 

     serialNumber validator: { 
      return ((serialNumber != null && legacyLookup == null) || (serialNumber == null && legacyLookup != null)) 
     } 
    } 
} 

Ich habe den Standard CRUD Bildschirme und versuchte, einen Eintrag für diese Domain-Klasse

information: Blah Blah 
serialNumber: 
legacyLookup: BLAHINDEX123 

Dieser stirbt in dem Validator mit der folgenden Meldung zu erstellen:

No such property: serialNumber for class: myproject.Sample 

Was ich bin fehlt?

Antwort

9

Es ist nicht notwendig, jede Eigenschaft mehrere Male darin zu haben; in der Tat brauchen Sie nur eine von ihnen tatsächlich eingeschränkt. Außerdem können Sie Eigenschaften nicht direkt anhand ihres Namens referenzieren. Es gibt Objekte, die an den Constraint Closure übergeben werden, um die Werte abzurufen (siehe docs). Wahrscheinlich der einfachste Weg, die ich gefunden habe, dies zu tun, ist wie folgt:

class Sample { 
    String information 
    String legacyLookup 
    String serialNumber 

    static constraints = { 
     information(nullable: true) 
     legacyLookup(validator: {val, obj-> 
      if((!val && !obj.serialNumber) || (val && obj.serialNumber)) { 
       return 'must.be.one' 
      } 
     }) 
    } 
} 

Und haben dann einen Eintrag in den messages.properties wie diese Datei:

must.be.one=Please enter either a serial number or a legacy id - not both 

Oder könnten Sie separate Nachrichten haben für jeder Zustand - beide eingegeben werden, oder beide leer sind wie folgt aus:

legacyLookup(validator: {val, obj-> 
    if(!val && !obj.serialNumber) { 
     return 'must.be.one' 
    } 
    if(val && obj.serialNumber) { 
     return 'only.one' 
    } 
}) 

und dann zwei Nachrichten in message.properties haben:

only.one=Don't fill out both 
must.be.one=Fill out at least one... 

Sie brauchen nichts von dem Zwang zurück, wenn kein Fehler vorhanden ist ...

+0

Das tat genau das, was ich brauchte. Ich dachte, dass ich die Validierung für beide Felder explizit benötige, aber die eine behandelt die andere. Vielen Dank! – GeoGriffin

0

Wenn Sie sicherstellen möchten, dass Sie "einen einzigen Wert" haben, wäre eine andere Option, ein generisches Feld namens serialNumberLegacyLookup zu erstellen, das die Felder serialNumber und legacyLookup repräsentieren würde. Dann könnten Sie Ihrer Domain-Klasse legacyLookup ein boolesches Feld hinzufügen, das standardmäßig false ist. Sie könnten dann den Wert über den Validator ausführen und analysieren, um festzustellen, ob es sich um einen "Seriennummer" oder einen "Legacy-Lookup" -Wert handelt. Wenn sich herausstellte, dass der Wert ein "Legacy-Lookup" -Wert ist, würden Sie den Boolean legacyLookup10 auf true setzen. Ich denke, dass dieser Ansatz aus einer UI-Perspektive weniger verwirrend sein würde (nur ein Feld für den Benutzer anstelle von zwei bedingten Feldern ausfüllen).

+0

Da der Code, mit dem ich arbeite, mit externen Legacy-Systemen interagiert, halte ich diese Lösung für nicht geeignet. Die Daten, die zu mir kommen, haben ein Feld oder das andere, aber sie sind als einzigartige Felder modelliert. Es kann einige Geschäftsregeln geben, die mir zu dieser Zeit unbekannt sind und die mein Verständnis des Modells beeinträchtigen könnten. Um mich von dieser Möglichkeit zu isolieren, werde ich sie getrennt halten. – GeoGriffin

0

ich mit diesem gleichen Szenario und die Lösung, die ich war gefunden konfrontiert wurde eine Getter-Methode zu erstellen und eine Einschränkung hinzufügen zu ihm.