hasMany独一无二的Grails [英] Grails unique with hasMany

查看:91
本文介绍了hasMany独一无二的Grails的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题是我询问这里的问题的扩展/组合此处

我的最终目标是将域类放在以下位置:

My end goal is to have domain classes where:


  1. 等于 code>和 hashCode @EqualsAndHashCode 产生的方法带 hasMany 属性
  2. 域类中属性的唯一约束需要 hasMany
  3. code>属性进行考虑
  4. 只要其中一个属性使其与已存在的实例不同,它就被认为是唯一的。

  1. The equals and hashCode methods generated by @EqualsAndHashCode take hasMany properties into account
  2. The unique constraint of a property in a domain class takes hasMany properties into account
  3. An instance of a domain class is considered unique so long as one of its properties makes it different from instances that already exist.

感谢@James Kleeh和@dmahapatro,我认为我很接近,但是第二点和第三点给我带来麻烦。

Thanks to @James Kleeh and @dmahapatro I think I'm close, but points 2 and 3 are giving me trouble.

我是第一次尝试t在测试我的需求时,在我的 FooTests.groovy 文件中进行了单元测试 testFooWithMockedBar 。我试图在该测试中使用 Bar.get(),但它不起作用。我不认为调用 mockForConstraintsTests 也可以。

I my first attempt at testing my requirements was the unit test testFooWithMockedBar in my FooTests.groovy file. I'm trying to use Bar.get() in that test, but it isn't working. I don't think the call to mockForConstraintsTests worked either.

我很确定我在我的下一个测试是 testFooWithoutMockedBar ,但我不确定测试是否按照我认为正在做的那样做,我将在后面解释。

I'm pretty sure I corrected this problem in my next test, testFooWithoutMockedBar, but I'm not sure the test is doing what I think it is doing as I will explain next.

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

After passing testFooWithoutMockedBar I tried to run the app in development mode to see if it worked as expected. Unfortunately the bars attribute in the line prop1(unique: ['prop2', 'prop3', 'bars']) in the file Foo.groovy is preventing Grails from creating the foo table in the database. Here is the error I get:

| 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 中使用自定义验证器:

I'm not sure if there is a groovy way to fix this or not. The only way I can think to fix it is with a custom validator in 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

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


推荐答案

尝试

try

@EqualsAndHashCode(includeFields=true)

@EqualsAndHashCode(callSuper=true)

这篇关于hasMany独一无二的Grails的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆