Grails与hasMany独特

时间:2013-08-20 21:45:36

标签: grails

此问题是我问herehere的问题的扩展/组合。

我的最终目标是将域类放在:

  1. equals生成的hashCode@EqualsAndHashCode方法将hasMany属性纳入帐户
  2. 域类中属性的unique约束将hasMany属性考虑在内
  3. 只要其中一个属性与已存在的实例不同,就认为域类的实例是唯一的。
  4. 感谢@James Kleeh和@dmahapatro我觉得我很接近,但是第2点和第3点给了我麻烦。

    我第一次尝试测试我的要求是我的testFooWithMockedBar文件中的单元测试FooTests.groovy。我正在尝试在该测试中使用Bar.get(),但它无效。我认为对mockForConstraintsTests的调用也不起作用。

    我很确定我在下一次测试中纠正了这个问题,testFooWithoutMockedBar,但我不确定测试是否正在按照我将要解释的那样进行。

    传递testFooWithoutMockedBar后,我尝试在开发模式下运行应用程序以查看它是否按预期工作。遗憾的是,文件bars中行prop1(unique: ['prop2', 'prop3', 'bars'])中的Foo.groovy属性阻止Grails在数据库中创建foo表。这是我得到的错误:

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

    我不确定是否有一种常规方法可以解决这个问题。我可以考虑修复它的唯一方法是使用Foo.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)
        }
    

    有没有更好的方法来做我想要的事情?

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

1 个答案:

答案 0 :(得分:0)

尝试

@EqualsAndHashCode(includeFields=true)

@EqualsAndHashCode(callSuper=true)