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