save() 没有flush不是保存记录吗?

kof*_*rts 1 grails

我正在玩 grails 3 应用程序。我使用简单的操作创建了这个简单的图书应用程序。它没有更新记录。

这是图书域名

package bookapp

class Book {

    String name

    static constraints = {
    }
}
Run Code Online (Sandbox Code Playgroud)

这是图书控制器

package bookapp

import grails.plugin.springsecurity.annotation.Secured

@Secured('ROLE_USER')
class BookController {

    def index() {

        [books: Book.findAll()]
    }

    def create(){

    }

    def save(){
        def book = new Book(params)
        book.save()

        redirect(action:'show', id:book.id)
    }

    def edit(Long id){
        [book: Book.get(id)]
    }

    def update(Long id){

        def book = Book.get(id)

        bindData(book, params)

        book.save()

        redirect(action:'show', id:book.id)

    }

    def show(Long id){
        [book: Book.get(id)]
    }

    def destroy(){

    }
}
Run Code Online (Sandbox Code Playgroud)

这是编辑视图页面

<h1> Edit Book Page</h1>

<g:form action="update" id="${book.id}">

    <g:textField name="name" value="${book.name}"></g:textField>

    <g:submitButton name="submit"></g:submitButton>

</g:form>
Run Code Online (Sandbox Code Playgroud)

当我在编辑页面并更改名称字段,然后单击提交按钮时。它不会更新这本书。如果我将更新操作更改为

 def update(Long id){

            def book = Book.get(id)

            bindData(book, params)

            book.save(flush:true)

            redirect(action:'show', id:book.id)

        }
Run Code Online (Sandbox Code Playgroud)

这是可行的。所以我的问题是为什么我们需要显式刷新?为什么 save() 不保存记录?我错过了什么吗?感谢帮助!

完整代码:

首先创建一个域Book如下

class Book {
    String name
    static constraints = {
    }
}
Run Code Online (Sandbox Code Playgroud)

创建图书控制器

class BookController {

    def index() {

        [books: Book.findAll()]
    }

    def create(){

    }

    def save(){
        def book = new Book(params)
        book.save()
        redirect(action:'show', id:book.id)
    }

    def edit(Long id){
        [book: Book.get(id)]
    }

    def update(Long id){
        def book = Book.get(id)
        book.properties = params
        book.save()
        redirect(action:'show', id:book.id)
    }

    def show(Long id){
        [book: Book.get(id)]
    }

    def destroy(Long id){
        Book.get(id).delete()
        redirect(action:'index')
    }
}
Run Code Online (Sandbox Code Playgroud)

意见

创建.gsp

<h1> Create Book Page</h1>

<g:form action="save">

    <g:textField name="name"></g:textField>

    <g:submitButton name="submit"></g:submitButton>

</g:form>
Run Code Online (Sandbox Code Playgroud)

编辑gsp

<h1> Edit Book Page</h1>

<g:form action="update" id="${book.id}">

    <g:textField name="name" value="${book.name}"></g:textField>

    <g:submitButton name="submit"></g:submitButton>

</g:form>
Run Code Online (Sandbox Code Playgroud)

索引.gsp

<g:each in="${books}" var="book">

    <h2><g:link action="show" id="${book.id}"> ${book.name} </g:link></h2>

</g:each>


<g:link controller="book" action="create">Create Book</g:link>
Run Code Online (Sandbox Code Playgroud)

显示.gsp

<h1> ${book.name} </h1>

<g:link action="edit" id="${book.id}">Edit</g:link>
<g:link action="destroy" id="${book.id}">Delete</g:link>
<g:link action="index">Back</g:link>
Run Code Online (Sandbox Code Playgroud)

删除和更新不能仅与 save() 一起使用。需要添加 save(flush:true)。谢谢!

更新: 这很奇怪。相同的代码适用于 grails 2。我尝试使用 grails 2.2。它仅不适用于 grails 3。我用来测试的 grails 3 版本是 grails 3.3.6。grails 3 中是否有任何改变打破了这一点?

更新2:

我现在已将删除操作转移到服务中,如下所示。

@Transactional
class BookService {

    def destroy(Long id) {

        def b = Book.get(id)
        b.delete()

    }
}
Run Code Online (Sandbox Code Playgroud)

在控制器中

class BookController {

    def bookService

    def destroy(Long id){
        bookService.destroy(id)
        redirect(action:'index')
    }
}
Run Code Online (Sandbox Code Playgroud)

并且查看要删除的代码是

<h1> ${book.name} </h1>

<g:link action="edit" id="${book.id}">Edit</g:link>
<g:link action="destroy" id="${book.id}">Delete</g:link>
<g:link action="index">Back</g:link>
Run Code Online (Sandbox Code Playgroud)

当我单击删除时,它会重定向到索引页面,但我仍然可以看到记录。我错过了什么吗?谢谢!

vir*_*ert 5

我在我曾经开发过的每个 Grails 应用程序中都看到过两个经典错误。所以不要灰心。

首先,虽然您可以在控制器中进行持久化,但您不应该将业务逻辑与路由和渲染分离,这就是服务的用途。

其次,当您进行数据库修改时,您应该使用事务。在 Grails 中,您可以使用 @Transactional 来做到这一点,您可以将其添加到方法或类中。一般来说,您不必执行flush:true,除非您需要已保存记录的id。@Transactional 可以采用许多参数来改变事务的工作方式: https://docs.grails.org/latest/guide/services.html#declarativeTransactions

不久前,我为 Grails 3 创建了这些架构图: https://github.com/virtualdogbert/Grails_Architecture

我还创建了此页面作为 Groovy/Grails 资源的位置: https: //github.com/virtualdogbert/Groovy_Links

希望有帮助。

对于删除,您在服务中的列表设置如下:

class BookService {

    @Transactional(readOnly = true)
    def listBooks() {
        Book.list()
    }
Run Code Online (Sandbox Code Playgroud)