我正在尝试使用Author和Book域类创建父子表单。视图工作正常,让我在创建新作者时输入书籍。但是,当我添加新作者和书籍并检查数据库(dbconsole)时,我在Author表中看到一条新记录,但没有记录添加到Book表中。你能告诉我我在这里错过了什么或做错了吗?
以下是我的域类:
作者:
package bookauthor1tomany
import org.apache.common.collections.list.*
import org.apache.commons.collections.ListUtils.*
class Author {
static constraints = {
}
String name
String category
List<Book> books = new ArrayList<>()
static hasMany = [ books:Book ]
static mapping = {
books cascade:"all-delete-orphan"
}
def getExpandableBookList() {
return LazyList.decorate(books, FactoryUtils.instantiateFactory(Book.class))
}
String toString(){
return "${name}" - "${category}"
}
}
图书
package bookauthor1tomany
class Book {
static constraints = {
}
String title
boolean _deleted
static transients = [ '_deleted' ]
static belongsTo = [ author:Author ]
def String toString() {
return title
}
}
AuthorController
我没有用控制器改变任何东西。这是Author控制器的默认生成保存方法。
@Transactional
def save(Author authorInstance) {
if (authorInstance == null) {
notFound()
return
}
if (authorInstance.hasErrors()) {
respond authorInstance.errors, view:'create'
return
}
authorInstance.save flush:true
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.created.message', args: [message(code: 'author.label', default: 'Author'), authorInstance.id])
redirect authorInstance
}
'*' { respond authorInstance, [status: CREATED] }
}
}
GSP的
create.gsp
<!DOCTYPE html>
<html>
<head>
<meta name="layout" content="main">
<g:set var="entityName" value="${message(code: 'author.label', default: 'Author')}" />
<title><g:message code="default.create.label" args="[entityName]" /></title>
</head>
<body>
<a href="#create-author" class="skip" tabindex="-1"><g:message code="default.link.skip.label" default="Skip to content…"/></a>
<div class="nav" role="navigation">
<ul>
<li><a class="home" href="${createLink(uri: '/')}"><g:message code="default.home.label"/></a></li>
<li><g:link class="list" action="index"><g:message code="default.list.label" args="[entityName]" /></g:link></li>
</ul>
</div>
<div id="create-author" class="content scaffold-create" role="main">
<h1><g:message code="default.create.label" args="[entityName]" /></h1>
<g:if test="${flash.message}">
<div class="message" role="status">${flash.message}</div>
</g:if>
<g:hasErrors bean="${authorInstance}">
<ul class="errors" role="alert">
<g:eachError bean="${authorInstance}" var="error">
<li <g:if test="${error in org.springframework.validation.FieldError}">data-field-id="${error.field}"</g:if>><g:message error="${error}"/></li>
</g:eachError>
</ul>
</g:hasErrors>
<g:form url="[resource:authorInstance, action:'save']" >
<fieldset class="form">
<g:render template="authortemp"/>
</fieldset>
<fieldset class="buttons">
<g:submitButton name="create" class="save" value="${message(code: 'default.button.create.label', default: 'Create')}" />
</fieldset>
</g:form>
</div>
</body>
</html>
_form.gsp
<%@ page import="BookAuthor1ToMany" %>
<div class="fieldcontain ${hasErrors(bean: authorInstance, field: 'books', 'error')} ">
<label for="books">
<g:message code="author.books.label" default="Books" />
</label>
<ul class="one-to-many">
<g:each in="${authorInstance?.books?}" var="b">
<li><g:link controller="book" action="show" id="${b.id}">${b?.encodeAsHTML()}</g:link></li>
</g:each>
<li class="add">
<g:link controller="book" action="create" params="['author.id': authorInstance?.id]">${message(code: 'default.add.label', args: [message(code: 'book.label', default: 'Book')])}</g:link>
</li>
</ul>
</div>
<div class="fieldcontain ${hasErrors(bean: authorInstance, field: 'name', 'error')} required">
<label for="name">
<g:message code="author.name.label" default="Name" />
<span class="required-indicator">*</span>
</label>
<g:textField name="name" required="" value="${authorInstance?.name}"/>
</div>
_authortemp.gsp
<div class="dialog">
<table>
<tbody>
<tr class="prop">
<td valign="top" class="name"><label for="name">Name:</label></td>
<td valign="top" class="value ${hasErrors(bean:authorInstance,field:'name','errors')}">
<input type="text" id="name" name="name" value="${fieldValue(bean:authorInstance,field:'name')}"/>
</td>
</tr>
<tr class="prop">
<td valign="top" class="name"><label for="category">Category:</label></td>
<td valign="top" class="value ${hasErrors(bean:authorInstance,field:'category','errors')}">
<input type="text" id="category" name="category" value="${fieldValue(bean:authorInstance,field:'category')}"/>
</td>
</tr>
<tr class="prop">
<td valign="top" class="name"><label for="books">Books:</label></td>
<td valign="top" class="value ${hasErrors(bean:authorInstance,field:'books','errors')}">
<g:render template="books" model="['authorInstance':authorInstance]" />
</td>
</tr>
</tbody>
</table>
</div>
_books.gsp
<script type="text/javascript">
var childCount = ${authorInstance?.books.size()} + 0;
function addChild() {
var htmlId = "book" + childCount;
var deleteIcon = "${resource(dir:'images/skin', file:'database_delete.png')}";
var templateHtml = "<div id='" + htmlId + "' name='" + htmlId + "'>\n";
templateHtml += "<input type='text' id='expandableBookList[" + childCount + "].title' name='expandableBookList[" + childCount + "].title' />\n";
templateHtml += "<span onClick='$(\"#" + htmlId + "\").remove();'><img src='" + deleteIcon + "' /></span>\n";
templateHtml += "</div>\n";
$("#childList").append(templateHtml);
childCount++;
}
</script>
<div id="childList">
<g:each var="book" in="${authorInstance.books}" status="i">
<g:render template='book' model="['book':book,'i':i]"/>
</g:each>
</div>
<input type="button" value="Add Book" onclick="addChild();" />
_book.gsp
<div id="book${i}">
<g:hiddenField name='expandableBookList[${i}].id' value='${book.id}'/>
<g:textField name='expandableBookList[${i}].title' value='${book.title}'/>
<input type="hidden" name='expandableBookList[${i}]._deleted' id='expandableBookList[${i}]._deleted' value='false'/>
<span onClick="$('#expandableBookList\\[${i}\\]\\._deleted').val('true'); $('#expandableBookList${i}').hide()">Delete</span>
</div>
答案 0 :(得分:0)
您不需要
List<Book> books = new ArrayList<>()
在您的域中。默认情况下,hasMany会为您提供书籍收藏。这可能会导致一些问题。此外,您是否已在控制器中进行调试,以确保在保存时填充书籍集合。