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