Grale einzigartig bei hasMany

Diese Frage ist eine Erweiterung / Kombination der Fragen, die ich gestellt habeHier undHier.

Mein Endziel ist es, Domainklassen zu haben, in denen:

Dasequals undhashCode Methoden generiert von@EqualsAndHashCode nehmenhasMany Eigenschaften berücksichtigenDasunique Einschränkung einer Eigenschaft in einer Domain-Klasse nimmthasMany Eigenschaften berücksichtigenEine Instanz einer Domänenklasse wird als eindeutig angesehen, solange sich eine ihrer Eigenschaften von bereits vorhandenen Instanzen unterscheidet.

Dank @James Kleeh und @dmahapatro denke ich, dass ich nah dran bin, aber die Punkte 2 und 3 bereiten mir Probleme.

Mein erster Versuch, meine Anforderungen zu testen, war der KomponententesttestFooWithMockedBar in meinemFooTests.groovy Datei. Ich versuche es zu benutzenBar.get() in diesem Test, aber es funktioniert nicht. Ich glaube nicht, dass der Anruf zumockForConstraintsTests hat auch geklappt.

Ich bin mir ziemlich sicher, dass ich dieses Problem in meinem nächsten Test behoben habe.testFooWithoutMockedBar, aber ich bin nicht sicher, ob der Test das tut, was ich denke, wie ich als nächstes erklären werde.

Nach dem ÜberholentestFooWithoutMockedBar Ich habe versucht, die App im Entwicklungsmodus auszuführen, um festzustellen, ob sie wie erwartet funktioniert. Leider ist diebars Attribut in der Zeileprop1(unique: ['prop2', 'prop3', 'bars']) in der DateiFoo.groovy verhindert, dass Grails diefoo Tabelle in der Datenbank. Hier ist der Fehler, den ich bekomme:

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

Ich bin mir nicht sicher, ob es eine gute Möglichkeit gibt, dies zu beheben oder nicht. Die einzige Möglichkeit, dies zu beheben, ist die Verwendung eines benutzerdefinierten Validators inFoo.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)
    }

Gibt es einen besseren Weg, um das zu tun, was ich will?

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

Antworten auf die Frage(1)

Ihre Antwort auf die Frage