【问题标题】:grails 1.3.7 - GORM misinterpretation of nullable reflective many-to-one relationship (possible bug?)grails 1.3.7 - GORM 对可空反射多对一关系的误解(可能的错误?)
【发布时间】:2012-04-24 20:52:37
【问题描述】:

我遇到了一些乍一看似乎是 Gorm 中的错误(grails 1.3.7)。我想我会在处理 jira 问题之前在这里发布问题,以防我弄错了。

问题来了:

我有一个域类,它引用同一个类的父对象,也可以有一个指向别名的指针,也属于同一个域类。

这是域类:

class Mydomain {
    String name
    Mydomain alias
    Mydomain parent
    Mydomain foo

    static constraints = {
        parent(nullable: true)
        alias(nullable: true)
        foo(nullable: true)
    }
}

如果我执行以下脚本:

Mydomain.list()*.delete()
def one=new Mydomain(name:'one').save()
new Mydomain(name:'two', parent:one).save()

Mydomain.list().each{
    println it.name
    println "parent:${it.parent?.name}"
    println "alias:${it.alias?.name}"
    println "foo:${it.foo?.name}"
    println "============================"
}    

我得到以下结果:

one
parent:null
alias:two
foo:null
============================
two
parent:one
alias:null
foo:null
============================

这意味着当我设置 two.parent=one 时,gorm 会继续设置 one.alias=two

我猜gorm这样做是因为它推断出onetwo之间存在双向关系,然后设置对象一个两个的引用。

我可以看到这种行为适用于 Author 和 Book 之间的双向关系(假设作者当然只写一本书),但在我的情况下这是危险的,因为 gorm 会覆盖一个没有任何关系的关系这样做。

所以我的问题是,我如何告诉 GORM 将其视为单向可为空的关系?

感谢您的任何想法

更新:商业案例

这是我尝试建模的业务案例。 公司有名称,可以有子公司、仓库、当地办事处等。这是在父关系的帮助下建模的,有效地创建了公司树:

class Company {
    String name
    Company parent
}

现在,这种组织结构的表示对每个人来说都不一样,有些人可能不在乎办公室级别,或者在乎小组级别。这就是为什么公司可以在并行表示中使用别名。它仍然是同一家公司,可以有不同的名称,但您希望能够通过别名关系在这些平行树组织之间导航。

class Company {
    String name
    Company parent
    Company alias
}

所以是的,与 self 有多种关系,但它们具有非常不同的含义,我知道 GORM 使用最常见的简单情况作为默认值,但我真的在 DSL 中尽我所能来指示 GORM做正确的事,但没有成功。

执行此操作的常规方法是使用 mappedBy 指令添加双向一对多关系:

class Company {
    String name
    Company alias

    static belongsTo=[parent:Company]
    static hasMany=[children:Company]
    static mappedBy=[children:'parent']
}

但在许多 GORM 文章中,由于严重的性能问题,不鼓励使用这种成语。这就是为什么我想要一个单向关系

Company ---(parent)---> Company

【问题讨论】:

标签: grails grails-orm


【解决方案1】:

这里不应该使用适当的约束吗?只是想知道,因为我做了以下更改,现在输出不同了

class Mydomain {
    String name
    Mydomain alias
    Mydomain foo

    static belongsTo = [parent:Mydomain]

    static constraints = {
        parent(nullable: true)
        alias(nullable: true)
        foo(nullable:true)
    }
}

测试输出(也许这是你所期望的)

one
null
null
============================
two
null
null
============================

如果您可以提供有关您的域场景的更多详细信息,我们可以对此进行扩展。否则,我认为 GORM 会自动设置基数,因为没有指定约束。

免责声明:我使用的是 Grails 2.0.1

更新(26/04/12): 考虑到业务案例,如下所示的改造对您有用吗?

class Mydomain {
    String name

    static belongsTo = [parent:Mydomain]

    static constraints = {
        parent(nullable: true)
    }
}

class MydomainAlias {

    Mydomain me 
    Mydomain alias

    static constraints = {
        me (unique: 'alias')
    }
}

本质上,这会将别名隔离到不同的表。 Grails 会自动为您生成外键依赖项。示例模式导出如下所示

create table mydomain (id bigint not null auto_increment, version bigint not null, name varchar(255) not null, parent_id bigint, primary key (id));
create table mydomain_alias (id bigint not null auto_increment, version bigint not null, alias_id bigint not null, me_id bigint not null, primary key (id), unique (alias_id, me_id));
alter table mydomain add index FKECA5F170DF99DE64 (parent_id), add constraint FKECA5F170DF99DE64 foreign key (parent_id) references mydomain (id);
alter table mydomain_alias add index FKA70D16C16A628AB6 (me_id), add constraint FKA70D16C16A628AB6 foreign key (me_id) references mydomain (id);
alter table mydomain_alias add index FKA70D16C1CA5FA6FE (alias_id), add constraint FKA70D16C1CA5FA6FE foreign key (alias_id) references mydomain (id);

【讨论】:

  • 这看起来很奇怪,如果示例按预期工作,则 two.parent sould == one,而不是 null!我在 grails 1.3.7 中尝试了您的 belongsTo 约束,但仍然遇到与上述相同的错误:一个 {parent==null, alias==two, foo==null), two {parent==null, alias==null, foo ==null}
  • 我将在 grails 2.0.1 中尝试并返回这里。非常感谢您抽出宝贵时间查看此内容!
  • 我将扩展我的问题以澄清业务案例。
  • 刚刚在 grails 2.0.1 中尝试了我上面的示例(为了更清晰而进行了修改),并得到了与 1.3.7 中相同的结果,即使添加了 belongsTo 指令。能否麻烦您再将澄清的测试用例粘贴到您的项目中?
  • 我使用了您在上面粘贴的相同脚本。那个没有修改。
【解决方案2】:

发布 JIRA 问题后 http://jira.grails.org/browse/GRAILS-9062?focusedCommentId=70641#comment-70641

以及邮件列表中的一些交流,

http://markmail.org/message/xcmcclr2lv7ecrbn

Graeme Rocher 提出了解决方案。

只需添加以下 mappedBy 闭包

static mappedBy = [
    parent: 'null',
    alias:'null',
    foo:'null'
]

这将指示 GORM 不要假设需要双向关系。

感谢大家的专业帮助!

【讨论】:

  • 我在 Grails 2.1.0 上试过这个,但它引发了一个异常:org.codehaus.groovy.grails.exceptions.GrailsDomainException: Non-existent mapping property [null] specified for property [parent] in类 [类 Mydomain]。这仍然允许吗?
  • 能否请您对 jira 问题添加评论并记录您的案例?
猜你喜欢
  • 2011-12-02
  • 1970-01-01
  • 1970-01-01
  • 2014-12-07
  • 2011-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-18
相关资源
最近更新 更多