我最近从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在读取实例时正确处理连接表,仍不确定为什么它不能正确地将节点保存到连接表。
(https://github.com/bwagner5/grailsCollectionsDebugApp/tree/master)
问题似乎是Grails Data Binder。 Spring Data Binder工作正常(默认情况下为2.2.x,您可以覆盖2.3.x中的Grails活页夹,但不能覆盖2.4.x) 我已经加入了JIRA但仍想看看现在是否有解决方法: https://jira.grails.org/browse/GRAILS-11638
答案 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
在Grails 2.4.2&amp;中测试如果仍有问题,可以共享示例应用程序。