0

我正在尝试利用 Grails 为一对多关联处理数据绑定的能力。我能够成功地分配给关系,但删除单个元素或所有元素都不起作用。

这是我的模型的示例:

class Location {
    Float latitude
    Float longitude
}

class Route {
    Location start
    Location stop

    static belongsTo: [courier: Courier]
}

class Courier {
    String name
    static hasMany = [pickups: Location]
}

class ScheduledCourier extends Courier {
    static hasMany = [routes: Route]

    static mapping = {
        routes(cascade: 'all-delete-orphan')
    }
}

通过网站创建一个新的 ScheduledCourier 对象时,我可以传递一个路由列表以自动与标记绑定,如下所示:

<input type="hidden" name="routes[0].latitude" value="5" />
<input type="hidden" name="routes[0].longitude" value="5" />
<input type="hidden" name="routes[1].latitude" value="10" />
<input type="hidden" name="routes[1].longitude" value="10" />

这在我的控制器中对我来说很好:

class CourierController {
    // Very simplistic save
    def saveScheduled = {
        def courier = new ScheduledCourier(params)
        courier.save()
    }

    // Very simplistic update
    def update = {
        def courier = Courier.get(params.id)
        courier.properties = params
        courier.save()
    }
}

如果我改用以下标记,我可以单步调试调试器并看到 routes 属性现在是 [] 并且对象保存得很好,但记录不会从数据库中删除。

<input type="hidden" name="routes" value="" />

另外,如果我这样发送标记:

<input type="hidden" name="routes[0].latitude" value="5" />
<input type="hidden" name="routes[0].longitude" value="5" />

courier.routes 不会更新为仅包含 1 个对象。

有没有人见过这种行为?

这是 Grails 1.3.7……至少现在是这样。

编写了一个重现此行为的集成测试:

public void testCourierSave() {
    def l1 = new Location(latitude: 5, longitude: 5).save(flush: true)
    def l2 = new Location(latitude: 10, longitude: 10).save(flush: true)

    def params = ["name": "Courier", "pickups[0].id": l1.id, "pickups[1].id": l2.id,
        "routes[0].start.id": l1.id, "routes[0].stop.id": l2.id,
        "routes[1].start.id": l2.id, "routes[1].stop.id": l1.id]

    def c1 = new ScheduledCourier(params).save(flush: true)

    assertEquals(2, c1.routes.size())

    params = [routes: ""]
    c1.properties = params
    c1.save(flush: true)
    c1.refresh()    // Since the Routes aren't deleted, this reloads them

    assertEquals(0, c1.routes.size())    // Fails

    assertEquals([], Route.findAllByCourier(c1))    // Fails if previous assert is removed
}
4

1 回答 1

1

我想知道是否正在发生以下情况:

传递params [routes:""]框架时忽略它,因为它只是一个空字符串。

同样<input type="hidden" name="routes[0].latitude" value="5" />,可能只是更新集合中的第零个路线条目,其他的不会被删除,因为你告诉它的是第零个路线的纬度值应该是 5,而不是现在应该是唯一的路线收藏。

为了得到你想要的效果,你需要routes.clear()在绑定参数之前添加一个。

要控制模型的状态何时持久保存到数据库,您可以使用Grails 中提供的Spring 事务性。如果后续处理失败,这将允许您恢复到对象的原始状态。例如:

Courier.withTransaction {status ->

  // Load the courier

  //clear the existing routes

  // bind the new properties

  // perform extra processing

  //if the object is invalid, roll back the changes
  status.setRollbackOnly()

}
于 2012-07-23T06:34:36.520 回答