2012-07-14 7 views
5

私は、私のドメインクラスに相互排他的な2つの外部キー、シリアル番号または従来のルックアップ値があるという問題があります。Grailsドメインクラスの2つのフィールドの作成とXOR検証はどのようにして行いますか?

特定のエントリに対してどのエントリがあるか分からないため、これらのエントリをnullableにしてカスタムの検証を追加して、1つの値しか持たないようにしました。私は何

No such property: serialNumber for class: myproject.Sample 

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)) 
     } 
    } 
} 

私は、デフォルトのCRUD画面を作成し、これは、次のメッセージとバリで死ぬこのドメインクラスのエントリを作成するために

information: Blah Blah 
serialNumber: 
legacyLookup: BLAHINDEX123 

を試してみました行方不明?

答えて

9

複数のプロパティを複数回持つ必要はありません。実際には、実際に制約されているのは1つだけです。また、名前でプロパティを直接参照することもできません。値を取得するために使用される制約クロージャに渡されるオブジェクトがあります(docs参照)。

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' 
      } 
     }) 
    } 
} 

をしてから、このようなファイルmessages.propertiesのエントリを持っています:

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

それとものために別々のメッセージを持っている可能性があり、次のように多分私はこれを行うために見つけた最も簡単な方法はありますmessage.propertiesに2つのメッセージを持って、その後

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

とを::

- 各条件が両方が入力されている、またはその両方は次のように空白です
only.one=Don't fill out both 
must.be.one=Fill out at least one... 

あなたはエラーがない場合の制約から何かを返す必要はありません...

+0

これはまさに私が必要としたことでした。私は両方のフィールドで明示的に検証が必要だと考えていましたが、一方は他方のフィールドを処理します。ありがとう! – GeoGriffin

0

「1つのみの値」を確保する場合は、serialNumberLegacyLookupという汎用フィールドを作成し、serialNumberフィールドとlegacyLookupフィールドの両方を表すオプションを使用することもできます。次に、legacyLookupというドメインクラスにブール値フィールドを追加すると、デフォルト値はfalseになります。その後、バリデータを介して値を実行し、それを解析して「シリアル番号」または「レガシー参照」値であるかどうかを調べることができます。値が「従来のルックアップ」値であると判明した場合、legacyLookupブール値をtrueに設定します。私は、このアプローチがUIの観点から混乱することは少ないと考えています(2つの条件付きフィールドの代わりにユーザーが記入する1つのフィールドのみ)。

+0

私が使用しているコードは外部のレガシーシステムとやり取りするので、私はこの解決策は適切ではないと思います。私に来るデータには1つのフィールドまたは他のフィールドがありますが、それらは固有のフィールドとしてモデル化されています。現時点では私にはわからないビジネスルールがいくつかあり、それがモデルの理解を損なう可能性があります。その可能性から自分自身を守るために、私はそれらを別々に保つつもりです。 – GeoGriffin

0

私はこの同じシナリオに直面していたし、私が見つけた解決策は、getterメソッドを作成し、制約を追加しましたそれに。

package myproject 

class Sample { 

    String information 
    String legacyLookup 
    String serialNumber 

    def getTarget(){ 
     if (legacyLookup && !serialNumber) { 
      return legacyLookup 
     } else if (!legacyLookup && serialNumber) { 
      return serialNumber 
     } else { 
      return null 
     } 
    } 

    static constraints = { 
     information(nullable: true) 
     legacyLookup(nullable: true) 
     serialNumber(nullable: true) 
     target(nullable: false) 
    } 
} 
関連する問題