2012-07-14 14 views
5

Tôi gặp sự cố trong đó lớp miền của tôi có hai khóa bên ngoài có khả năng loại trừ lẫn nhau, một số sê-ri hoặc giá trị tra cứu cũ.Làm cách nào để tạo và xác thực XOR cho hai trường trong một lớp miền Grails?

Vì tôi không chắc mình sẽ có cái nào cho bất kỳ mục nhập cụ thể nào, tôi đã làm cho cả hai có thể vô hiệu và thêm xác thực tùy chỉnh để đảm bảo tôi có một và chỉ một giá trị.

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

Tôi tạo ra các màn hình CRUD mặc định và cố gắng để tạo ra một mục nhập cho này lớp miền

information: Blah Blah 
serialNumber: 
legacyLookup: BLAHINDEX123 

này chết trong validator với thông báo sau:

No such property: serialNumber for class: myproject.Sample 

Tôi gì còn thiếu?

Trả lời

9

Có mỗi thuộc tính trong đó nhiều lần là không cần thiết; trong thực tế, bạn chỉ cần một trong số họ thực sự bị ràng buộc. Ngoài ra, bạn không thể chỉ tham chiếu các thuộc tính trực tiếp theo tên của chúng. Có các đối tượng được chuyển đến kết thúc ràng buộc được sử dụng để lấy các giá trị (xem docs). Có lẽ là cách đơn giản nhất tôi đã tìm thấy để làm điều này là như sau:

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

Và sau đó có một mục trong messages.properties nộp như thế này:

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

Hoặc bạn có thể có tin nhắn riêng cho mỗi điều kiện - cả hai đều bước vào, hoặc cả hai đều trống như thế này:

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

Và sau đó có hai thông điệp trong message.properties:

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

Bạn không cần phải trả lại bất cứ điều gì từ những khó khăn nếu không có lỗi ...

+0

Điều này đã làm chính xác những gì tôi cần. Tôi đã nghĩ rằng tôi cần xác nhận một cách rõ ràng trên cả hai lĩnh vực, nhưng một trong những xử lý khác. Cảm ơn! – GeoGriffin

0

Nếu bạn muốn đảm bảo bạn có "một và chỉ một giá trị", một tùy chọn khác sẽ là tạo một trường chung có tên là serialNumberLegacyLookup sẽ đại diện cho cả hai trường serialNumberlegacyLookup. Sau đó, bạn có thể thêm một trường boolean vào lớp tên miền của bạn được gọi là legacyLookup sẽ mặc định là false. Sau đó, bạn có thể chạy giá trị thông qua trình xác thực và phân tích cú pháp để xem đó có phải là "số sê-ri" hay giá trị "tra cứu cũ" hay không. Nếu giá trị hóa ra là giá trị "tra cứu cũ" thì bạn sẽ đặt số boolean legacyLookup thành true. Tôi nghĩ cách tiếp cận này sẽ ít khó hiểu hơn từ góc độ giao diện người dùng (chỉ một trường để người dùng điền vào thay vì hai trường có điều kiện).

+0

Vì mã tôi đang làm việc có tương tác với các hệ thống kế thừa bên ngoài, tôi không nghĩ giải pháp này là phù hợp. Dữ liệu đến với tôi có một trường hoặc trường khác, nhưng chúng được mô hình hóa thành các trường duy nhất. Có thể có một số quy tắc kinh doanh mà tôi không biết vào thời điểm này có thể phá vỡ sự hiểu biết của tôi về mô hình. Để ngăn cách bản thân mình khỏi khả năng đó, tôi sẽ giữ chúng riêng biệt. – GeoGriffin

0

tôi đã phải đối mặt với cùng một kịch bản này và các giải pháp tôi thấy là tạo ra một phương thức getter và thêm một hạn chế cho nó.

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