Grails - 从数据绑定的hasMany关联列表中删除项目?

时间:2010-04-28 14:35:52

标签: data-binding grails groovy dns associations

Grails提供了自动创建域对象并将其绑定到hasMany列表的功能,如grails user guide中所述。

因此,例如,如果我的域对象“作者”具有许多“书籍”对象的列表,我可以使用以下标记(来自用户指南)创建和绑定它们:

<g:textField name="books[0].title" value="the Stand" /> 
<g:textField name="books[1].title" value="the Shining" /> 
<g:textField name="books[2].title" value="Red Madder" /> 

在这种情况下,如果指定的任何书籍尚不存在,Grails将创建它们并适当地设置其标题。如果指定的索引中已有书籍,则会更新其标题并保存。我的问题是:是否有一些简单的方法告诉Grails从数据绑定的“书籍”协会中删除其中一本书?

最明显的方法是省略与要删除的域实例对应的表单元素;不幸的是,根据用户指南,这不起作用:

  

然后Grails会自动创建   定义的新实例   位置。如果你“跳过”了一些   中间的元素......然后是Grails   将自动创建实例   之间。

我意识到特定的解决方案可以设计为命令对象的一部分,或者作为特定控制器的一部分 - 但是,在我的应用程序中,跨多个域对象以及许多不同的关联,对此功能的需求会反复出现对象类型。因此,一般的解决方案是理想的。有谁知道Grails中是否包含这样的内容?

6 个答案:

答案 0 :(得分:12)

我自己也遇到过这个问题。这很容易解决。 Grails使用java.util.Set来表示列表。您可以使用clear()方法擦除数据,然后添加所需的数据。

//clear all documents
bidRequest.documents.clear()

//add the selected ones back
params.documentId.each() {
    def Document document = Document.get(it)
    bidRequest.documents.add(document)
    log.debug("in associateDocuments: added " + document)
};

//try to save the changes
if (!bidRequest.save(flush: true)) {
    return error()
} else {
    flash.message = "Successfully associated documents"
}

我敢打赌,如果你不想“清除()”所有数据,你可以使用“remove()”方法做同样的事情。

答案 1 :(得分:11)

removeFrom*

与addTo方法相反,它从关联中删除实例。

实施例

def author = Author.findByName("Stephen King")

def book = author.books.find { it.title = 'The Stand' }

author.removeFromBooks(book)

答案 2 :(得分:4)

有关使用GORM删除子对象集合的详细说明,请查看此博客文章的“删除子级”部分 - GORM gotchas part 2

建议阅读,系列的第1和第3部分也是如此。

答案 3 :(得分:0)

我刚刚开始自己​​学习Grails,并将您的问题视为一项有趣的研究练习。我不认为你可以使用传统的数据绑定机制 - 因为它在幕后使用某种懒惰的地图填充空白。那么为了实现你的目标,你的“保存”方法(或者它是一个函数吗?)不太可能包含以下内容:

def Book = new Book(params)

您需要一种机制来修改控制器的“保存”方法。

经过一些研究,我了解到您可以修改脚手架模板,该模板负责生成控制器代码或运行时方法。您可以通过运行“ grails install-templates ”获取Grails使用的所有模板的副本,您需要修改的模板文件称为“ Controller.groovy

理论上,您可以通过这种方式修改整个应用程序的“保存”方法。

大!您可能认为现在需要做的就是修改模板中的保存方法,以便迭代参数图中的对象条目(例如书籍),保存和删除。


但是,我认为您所需的解决方案仍然可能存在很大问题。我的直觉告诉我,为什么你建议的机制是一个坏主意有很多原因。

出于某种原因,我不知道你有一个分页的书籍清单。这是否意味着您的“保存”可以删除除当前可见页面之外的整个数据库表?好的,我们假设您设法计算出每个页面上显示的项目数量,如果列表已排序,那么它不再按数字顺序排列 - 您现在删除了什么?

表单中的多个提交按钮可能是更好的方法(例如保存更改,添加,删除)。我没有在Grails中尝试过这种事情,但理解actionSubmit应该可以帮助您实现多个提交按钮。我当然习惯在Struts中做这种事情!

HTH

答案 4 :(得分:0)

我刚刚遇到同样的问题。

我的应用程序的域非常简单:它具有与Header对象具有hasMany关系的Stub对象。由于Header对象没有自己的生命,因此它们完全由Stub控制器和视图管理。

域类定义:

class Stub {
List headers = new ArrayList(); 
static hasMany = [headers:Header]
static mapping = {headers lazy: false}
}

class Header {
String value
static belongsTo = Stub     
}

我尝试了“clear and bind”方法,但最终结果是“清除”对象在数据库中遗留下来,而grails将只为那些未从关系中删除的对象创建新实例。它看起来似乎从用户的角度来看,但它会在数据库中留下大量的垃圾对象。

控制器的update()方法中的代码是:

stubInstance.headers.clear()
stubInstance.properties = params

一个例子:在编辑这种关系的一面时,我有(对于id为1的给定Stub):

<g:textField name="headers[0].value" value="zero" id=1 />
<g:textField name="headers[1].value" value="one" id=2 />
<g:textField name="headers[2].value" value="two" id=3 />

在数据库中有3个Header实例:

id=1;value="zero"
id=2;value="one"
id=3;value"two"

删除标题“one”并保存Stub对象后,数据库将包含标题:

id=1;value="zero"
id=2;value="one"
id=3;value"two"
id=4;value="zero"
id=5;value="two"

,Stub对象现在与ID为4且id = 5 ...

的Headers关联

此外,如果没有清除列表,如果提交的request.headers列表中没有索引,则数据绑定grails将使该位置的现有对象保持不变。

我遇到的解决方法是绑定数据,然后检查Stub的标头中是否有提交列表中不存在的元素并将其删除。

这看起来像一个非常简单的场景,是不是有任何内置功能来解决它​​? 必须编写自己的同步逻辑来维护关系有点过分,特别是当使得它变得非常重要的怪癖是由grails本身引起的时候。

删除怎么样,不应该从数据库中删除clear()'ed元素?我错过了关系或域对象定义中的某些内容吗?

答案 5 :(得分:0)

class Stub {
  List headers = new ArrayList(); 
  static hasMany = [headers:Header]
  static mapping = {
  headers lazy: false
  **headers cascade: "all-delete-orphan"**
   }
  }

class Header {
    String value
    static belongsTo = Stub     
 }

我已经在关系的拥有方添加了cascade属性。现在,如果您尝试保存存根,它将负责从集合中删除已删除的项目并从DataBase中删除它们。