Griales únicos con hasMany

Esta pregunta es una extensión / combinación de las preguntas que hiceaquí yaquí.

Mi objetivo final es tener clases de dominio donde:

losequals yhashCode métodos generados por@EqualsAndHashCode tomarhasMany propiedades en cuentalosunique La restricción de una propiedad en una clase de dominio tomahasMany propiedades en cuentaUna instancia de una clase de dominio se considera única siempre y cuando una de sus propiedades la haga diferente de las instancias que ya existen.

Gracias a @James Kleeh y @dmahapatro, creo que estoy cerca, pero los puntos 2 y 3 me están dando problemas.

Mi primer intento de probar mis requisitos fue la prueba de la unidad.testFooWithMockedBar en miFooTests.groovy expediente. Estoy tratando de usarBar.get() En esa prueba, pero no está funcionando. No creo que la llamada amockForConstraintsTests funcionó bien

Estoy bastante seguro de que corregí este problema en mi próxima prueba,testFooWithoutMockedBar, pero no estoy seguro de que la prueba esté haciendo lo que creo que está haciendo, como explicaré a continuación.

Después de pasartestFooWithoutMockedBar Intenté ejecutar la aplicación en modo de desarrollo para ver si funcionaba como se esperaba. Desafortunadamente, elbars atributo en la lineaprop1(unique: ['prop2', 'prop3', 'bars']) en el archivoFoo.groovy está evitando que Grails cree elfoo Tabla en la base de datos. Aquí está el error que recibo:

| Error 2013-08-20 16:17:52,249 [localhost-startStop-1] ERROR hbm2ddl.SchemaExport  - Unsuccessful: create table foo (id bigint not null auto_increment, version bigint not null, prop1 varchar(255) not null, prop2 varchar(255) not null, prop3 varchar(255) not null, primary key (id), unique (foo_bars_id, prop3, prop2, prop1)) ENGINE=InnoDB
| Error 2013-08-20 16:17:52,250 [localhost-startStop-1] ERROR hbm2ddl.SchemaExport  - Key column 'foo_bars_id' doesn't exist in table
| Error 2013-08-20 16:17:52,309 [localhost-startStop-1] ERROR hbm2ddl.SchemaExport  - Unsuccessful: alter table foo_bar add index FKD76E651A96EEE146 (foo_bars_id), add constraint FKD76E651A96EEE146 foreign key (foo_bars_id) references foo (id)
| Error 2013-08-20 16:17:52,310 [localhost-startStop-1] ERROR hbm2ddl.SchemaExport  - Can't create table 'foobar.#sql-474_8c' (errno: 150)

No estoy seguro de si hay una manera maravillosa de arreglar esto o no. La única forma en que puedo pensar para solucionarlo es con un validador personalizado enFoo.groovy:

class Foo {

...

    boolean isUnique
    static transients = ['isUnique']

    static constraints = {
        isUnique(
            validator: { val, obj ->
                def rslt = true
                for(foo in Foo.getAll()) {
                    if (foo == obj) {
                        rslt = false
                        break
                    }
                }
                return rslt
            }
        )
        bars(nullable: false)
    }

¿Hay una mejor manera de hacer lo que quiero?

Foo.groovy

package foobar

@groovy.transform.EqualsAndHashCode
class Foo {

    String prop1
    String prop2
    String prop3

    Set<Bar> bars
    static hasMany = [bars: Bar]

    static constraints = {
        prop1(unique: ['prop2', 'prop3', 'bars']) // The 'bars' in this line is preventing Grails from creating the foo table in the database.
        bars(nullable: false)
    }
}

Bar.groovy

package foobar

@groovy.transform.EqualsAndHashCode
class Bar {
    String prop1
}

FooTests.groovy

package foobar

import grails.test.mixin.*
import org.junit.*

@TestFor(Foo)
@Mock(Bar)
class FooTests {

    void testFooWithMockedBar() {

        // Create existing instances to validate against
        mockForConstraintsTests(Bar, [
                new Bar(prop1: "a"),
                new Bar(prop1: "b"),
                new Bar(prop1: "c"),
                new Bar(prop1: "d")
            ]
        )
        mockForConstraintsTests(Foo, [
                new Foo(prop1: "a", prop2: "b", prop3: "c", bars: [Bar.get(1), Bar.get(2)])
            ]
        )

        // Validation should fail if all properties are null
        def foo = new Foo()
        assert !foo.validate()
        assert "nullable" == foo.errors["prop1"]
        assert "nullable" == foo.errors["prop2"]
        assert "nullable" == foo.errors["prop3"]
        assert "nullable" == foo.errors["bars"]

        // Test unique constraints
        foo = new Foo(prop1: "a", prop2: "b", prop3: "c", bars: [Bar.get(1), Bar.get(2)])

        assert !foo.validate()
        assert "unique" == foo.errors["prop1"]

        // Validation should pass with all unique, not null properties
        foo = new Foo(prop1: "a", prop2: "b", prop3: "c", bars: [Bar.get(3), Bar.get(4)])
        assert foo.validate()

        // Test equals and hashCode
        assert foo == new Foo(prop1: "a", prop2: "b", prop3: "c", bars: [Bar.get(3), Bar.get(4)])
    }

    void testFooWithoutMockedBar() {

        // Create existing instances to validate against
        def bars1 = [new Bar(prop1: "a"), new Bar(prop1: "b")]
        def bars2 = [new Bar(prop1: "c"), new Bar(prop1: "d")]
        mockForConstraintsTests(Foo, [
                new Foo(prop1: "a", prop2: "b", prop3: "c", bars: bars1)
            ]
        )

        // Validation should fail if all properties are null
        def foo = new Foo()
        assert !foo.validate()
        assert "nullable" == foo.errors["prop1"]
        assert "nullable" == foo.errors["prop2"]
        assert "nullable" == foo.errors["prop3"]
        assert "nullable" == foo.errors["bars"]

        // Test unique constraints
        foo = new Foo(prop1: "a", prop2: "b", prop3: "c", bars: bars1)

        assert !foo.validate()
        assert "unique" == foo.errors["prop1"]

        // Validation should pass
        foo = new Foo(prop1: "a", prop2: "b", prop3: "c", bars: bars2)
        assert foo.validate()

        // Test equals and hashCode
        assert foo != new Foo(prop1: "a", prop2: "b", prop3: "c", bars: bars1)
        assert foo == new Foo(prop1: "a", prop2: "b", prop3: "c", bars: bars2)
    }
}

Respuestas a la pregunta(1)

Su respuesta a la pregunta