hasMany save没有在Grails 2.4.2升级上工作

时间:2014-07-21 17:04:35

标签: grails gorm

我最近从Grails 2.2.5升级到2.4.2。升级后,很多我的hasMany关系都没有保存。

例如:

Domains:
    class Node {
        String name
        String description

        static belongsTo = CustomGlobe
        static hasMany = [containers: Container]
    }

    class Container {
        String name
        CustomGlobe customGlobe

        static belongsTo = Node
        static hasMany = [nodes: Node]
    }

    class CustomGlobe {
        String name

        static belongsTo = CustomLocation
        static hasMany = [customLocations: CustomLocation, nodes: Node]
    }

    class CustomLocation {
        String name
        String description
    }

在执行事务的服务上,我确实在类def之上添加了@Transactional。我还尝试按Grails 2.4.2: Strange cascading save behaviour in nested transactions添加@Transactional(propagation = Propagation.REQUIRES_NEW)。如果我回滚Grails升级(相同的控制器,服务和视图代码),节点集将保持正确,但是,使用Grails 2.4.2则不会。通过打印对象的节点,我还在保存之前和之后检查了它,并且它显示在控制台上,但是当我的应用程序重定向到列表视图时,它不会显示,也不会在任何地方保留。

- UPDATE-- 这仍然发生在Grails 2.4.3中 我也相信它可能与联接表有关,但我无法弄清楚原因。在params绑定之后,Container有节点连接到它,但在.save()之后,它不会持久化到连接表。

- UPDATE-- 抱歉,Domain类代码的帖子中有一个错误,它已经更新,现在是正确的。希望有人可以对我现在失踪的内容有所了解。

问题出现时Nodes集合未持久存储到NODE_CONTAINERS表中的Container实例。

- UPDATE-- 问题仍在继续。在调试时,我使用Grails数据源创建了一个新的groovy Sql实例,并手动将节点插入到NODE_CONTAINERS表中。在查看Container show gsp时,所有内容都正确保存并正确调用。因此看起来GORM在读取实例时正确处理连接表,仍不确定为什么它不能正确地将节点保存到连接表。

用于演示错误的示例应用程序:

  1. 使用Grails 2.2.5(2.2.5分支)
  2. 的工作申请
  3. 使用Grails 2.4.3(MASTER分支)
  4. 描述上述错误的应用程序

    https://github.com/bwagner5/grailsCollectionsDebugApp/tree/master

    Grails Data Binder:

    问题似乎是Grails Data Binder。 Spring Data Binder工作正常(默认情况下为2.2.x,您可以覆盖2.3.x中的Grails活页夹,但不能覆盖2.4.x) 我已经加入了JIRA但仍想看看现在是否有解决方法: https://jira.grails.org/browse/GRAILS-11638

2 个答案:

答案 0 :(得分:2)

我建议实际添加单独的连接类,这也是Burt Beckwith提出的建议,您将在Grails Spring Security Core项目中找到这种做法。例如,只有您的Node和Container类,您最终会得到:

class Node {
    String name
    String description
    Set<NodeContainer> nodeContainers = []
    static hasMany = [nodeContainers: NodeContainer]
}

class Container {
    String name
    CustomGlobe customGlobe

    //potentially add a helper method for fetching the nodes, but no GORM specification should be made on this class
}


class NodeContainer {
    Container container
    Node node

    static NodeContainer addNodeContainer(Node node, Container container){
        def n = findByNodeAndContainer(node, container)
        if(!n){
            n = new NodeContainer(container: container)
            node.addToContainers(n)
            n.save()
        }  
    }

    // Other helper methods such as remove and table mappings if necessary
}

通过这种方式,您可以一次创建和删除一个连接,而不是要求hibernate加载整个Set,然后添加/删除项目。您还删除了在两个类上都有hasMany的需要,这可以在大型集上具有性能并节省问题。我通过实施这种模式设法解决了所有时髦的保存问题。祝你好运,我希望这会有所帮助!

答案 1 :(得分:1)

许多人应该只拥有一个拥有者。基于此,您需要对Node域类进行一次修改,并使用下面的示例,相应地填充连接表:

// Modification in Node
// Remove this belongsTo
// belongsTo should be only in the child side of m-m relationship
// static belongsTo = CustomGlobe

然后按照此示例(在BootStrap.groovy中尝试)查看填充表NODE_CONTAINERS表,如下所示:

def node = new Node(name: "Node1", description: "Desc1")
def cg = new CustomGlobe(name: "CG1")

def cl1 = new CustomLocation(name: "CL1", description: "Cust Location 1")
def cl2 = new CustomLocation(name: "CL2", description: "Cust Location 2")

[cl1, cl2].each { cg.addToCustomLocations it }

cg.save()

def cont1 = new Container(name: "Cont1", customGlobe: cg)
def cont2 = new Container(name: "Cont2", customGlobe: cg)

// After removing one of the belongsTo the cascading behavior will not be
// achieved. So the other side of many-many has to be saved explicitly.
def node2 = new Node(name: "Node2", description: "Desc2").save()
def node3 = new Node(name: "Node3", description: "Desc3").save()
cont2.addToNodes( node2 ).addToNodes( node3 ).save()

[cont1, cont2].each { node.addToContainers it}

node.save flush: true

enter image description here

在Grails 2.4.2&amp;中测试如果仍有问题,可以共享示例应用程序。