我正在尝试利用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
}
答案 0 :(得分:1)
我想知道是否发生了以下情况:
传递params [routes:""]
框架时忽略它,因为它只是一个空字符串。
类似地<input type="hidden" name="routes[0].latitude" value="5" />
可能只是更新集合中的第0个路由条目,其他的不会被删除,因为你告诉它的是第0个路由的纬度值应该是5,而不是现在应该是该系列中唯一的路线。
要获得所需的效果,您需要在绑定参数之前添加routes.clear()
。
要控制何时将模型的状态持久保存到数据库,您可以使用Grails中提供的Spring transactionality。如果后续处理失败,这将允许您恢复到对象的原始状态。例如:
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()
}