2014-07-21 40 views
1

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

例如:

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 
    } 

在执行我添加了@Transactional类DEF上述交易的服务。我还试图根据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绑定后具有附加的节点,但在.save()之后,它不会保留到连接表中。

--UPDATE-- 对不起,域类代码的帖子中有错误,它已被更新,现在是正确的。希望有人能够阐明我现在想念的东西。

Nodes集合未被持久保存到NODE_CONTAINERS表中的Container实例时发生此问题。

--UPDATE - 问题正在进行中。在调试时,我使用Grails数据源创建了一个新的Groovy Sql实例,并手动将节点插入到NODE_CONTAINERS表中。一切正确保存并在查看容器show gsp时被正确调用。所以看起来,GORM在读取实例时正确地处理了连接表,仍然不确定为什么它没有正确地将节点保存到连接表中。

应用示例演示的错误:

  1. 工作的应用使用Grails 2.2.5(2.2.5分支)以上使用Grails 2.4.3(MASTER分支)描述
  2. 应用表现出错误

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

Grails的数据粘合剂:

这个问题似乎是Grails数据绑定器。 Spring Data Binder工作正常(在2.2.x中是默认的,你可以在2.3.x中重写Grails联编程序,但不能在2.4.x中) 我已经放入了JIRA,但仍然希望看看是否有解决方法现在: https://jira.grails.org/browse/GRAILS-11638

+0

您是否正确升级了所有插件?一些老插件与新的Grails存在错误。 – wwarlock

+0

是的,我没有正确升级。它似乎不喜欢joinTable。如果我在绑定参数数据后打印对象,我可以看到节点的集合,但在保存()后,它们不见了。我检查了hasErrors,它没有任何东西。其他一切都正确(名称和说明)。有什么想法吗? –

+0

'Node'有许多'Container','Container'有很多'Node',但'Node'属于'CustomGlobe',而不是'Container'。那是故意的吗? –

回答

2

我会推荐实际添加单独的连接类,这也是Burt Beckwith提出的建议,您会发现这个练习在Grails Spring Security Core项目中使用。例如只用你的节点和容器类,你会最终:

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 
} 

这样,要创建和删除的连接一次一个,而不是要求的休眠加载整个设置,然后添加/从中删除项目。你也不需要在这两个类上都有hasMany,它可以在大集合上具有性能并且可以节省问题。我设法通过实施这种模式来解决我所有的时髦保存问题。祝你好运,我希望这有助于!

+0

有趣的是,我观看了Burt的视频,但是我在交易中遇到了一些问题。 r创建,然后是NodeContainer中的节点(因为容器必须先有一个ID)。在更新容器时,我首先将节点保存到NodeContainer,然后保存容器。如果我通过添加节点进行更新,一切都按预期工作。如果我删除了节点,我会得到一个具有相同标识符值的不同对象已与该会话相关联:[NodeContainer ...] –

+0

您需要确保已经在Node和Node上调用了save()容器,然后从它们创建NodeContainer。这可能是你的问题的原因。 – th3morg

1

多对多应该只有一个拥有方。在此基础上,你将需要一个修改Node域类,并与下面的示例中,连接表得到相应的填充:

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

然后按照这个样本(自举尝试。常规)看到连接表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 &可以共享示例应用程序,如果还存在一定的问题。

+0

好吧,我改变了关系,但问题仍然存在。 –

+0

你可以在github上分享一个可以看到的最小样本示例吗? – dmahapatro

+0

我可以尝试将裸露的最小应用发布到github上,需要一些时间。该应用程序是一个大型企业应用程序的一部分,具有很多依赖性(糟糕的庞然大物,我知道:()。因为我仍在调试此问题,我使用Grails数据源创建了一个新的Sql实例,并手动将节点插入到NODE_CONTAINERS表中,保存正确,并在查看容器show gsp(添加了更新问题)时被召回。也许这会引发一些事情,但我看到我是否可以创建裸机应用程序 –