Grails自定义侦听器,更新属性会生成其他事件吗?
我需要从客户机域中的一些地址字段计算coords,因此为了将域类与此要求解耦,我添加了一个自定义侦听器,它使用GoogleMapsAPI来获取正确的值 一切都正常,但调试时我意识到更新监听器中的域属性会启动另一个更新事件,并且我的监听器会连续为每次更新调用Google API两次 有人遇到了这个问题??我做错了什么 域:Grails自定义侦听器,更新属性会生成其他事件吗?,grails,google-maps-api-3,listener,gorm,Grails,Google Maps Api 3,Listener,Gorm,我需要从客户机域中的一些地址字段计算coords,因此为了将域类与此要求解耦,我添加了一个自定义侦听器,它使用GoogleMapsAPI来获取正确的值 一切都正常,但调试时我意识到更新监听器中的域属性会启动另一个更新事件,并且我的监听器会连续为每次更新调用Google API两次 有人遇到了这个问题??我做错了什么 域: class Client{ String address String city String country String postalCode doub
class Client{
String address
String city
String country
String postalCode
double lat
double lng
....
}
class GoogleMapsService{
static transactional=false
def grailsApplication
def geocode(String address){
address=address.replaceAll(" ", "+")
def urlApi=grailsApplication.config.googleMaps.apiUrl+"&address=${address}"
def urlJSON = new URL(urlApi)
def geoCodeResultJSON = new JsonSlurper().parseText(urlJSON.getText())
return geoCodeResultJSON
}
}
class ClientListener extends AbstractPersistenceEventListener{
public boolean supportsEventType(Class<? extends ApplicationEvent> eventClass) {
switch(eventClass){
case [PreInsertEvent,
PreUpdateEvent,
PostInsertEvent,
PostUpdateEvent,
PostDeleteEvent]:
return true
default:
return false
}
}
protected void onPersistenceEvent(AbstractPersistenceEvent event) {
if(!(event.entityObject instanceof Client)){
return
}
switch(event.eventType) {
//GOOGLE MAPS geocode
case [EventType.PreInsert,EventType.PreUpdate]:
this.updateCoords(event.entityObject)
break
//OTHER STUFF (notifications, no changing inside)
case EventType.PostUpdate:
//....
}
}
private String composeAddress(Client cli){
def resul=[cli.address,cli.city,cli.country,cli.postalCode]
return resul.findAll{it}.join(",")
}
private void updateCoords(Client cli){
def fullAddress=this.composeAddress(cli)
if(fullAddress){
def coords=googleMapsService.geocode(fullAddress)
if (coords.status=="OK"){
//**IMPORTANT STUFF THESE TWO LINES RAISE AN EVENT
cli.lat=coords.results.geometry.location.lat[0]
cli.lng=coords.results.geometry.location.lng[0]
}
}
}
}
服务:
class Client{
String address
String city
String country
String postalCode
double lat
double lng
....
}
class GoogleMapsService{
static transactional=false
def grailsApplication
def geocode(String address){
address=address.replaceAll(" ", "+")
def urlApi=grailsApplication.config.googleMaps.apiUrl+"&address=${address}"
def urlJSON = new URL(urlApi)
def geoCodeResultJSON = new JsonSlurper().parseText(urlJSON.getText())
return geoCodeResultJSON
}
}
class ClientListener extends AbstractPersistenceEventListener{
public boolean supportsEventType(Class<? extends ApplicationEvent> eventClass) {
switch(eventClass){
case [PreInsertEvent,
PreUpdateEvent,
PostInsertEvent,
PostUpdateEvent,
PostDeleteEvent]:
return true
default:
return false
}
}
protected void onPersistenceEvent(AbstractPersistenceEvent event) {
if(!(event.entityObject instanceof Client)){
return
}
switch(event.eventType) {
//GOOGLE MAPS geocode
case [EventType.PreInsert,EventType.PreUpdate]:
this.updateCoords(event.entityObject)
break
//OTHER STUFF (notifications, no changing inside)
case EventType.PostUpdate:
//....
}
}
private String composeAddress(Client cli){
def resul=[cli.address,cli.city,cli.country,cli.postalCode]
return resul.findAll{it}.join(",")
}
private void updateCoords(Client cli){
def fullAddress=this.composeAddress(cli)
if(fullAddress){
def coords=googleMapsService.geocode(fullAddress)
if (coords.status=="OK"){
//**IMPORTANT STUFF THESE TWO LINES RAISE AN EVENT
cli.lat=coords.results.geometry.location.lat[0]
cli.lng=coords.results.geometry.location.lng[0]
}
}
}
}
事件侦听器:
class Client{
String address
String city
String country
String postalCode
double lat
double lng
....
}
class GoogleMapsService{
static transactional=false
def grailsApplication
def geocode(String address){
address=address.replaceAll(" ", "+")
def urlApi=grailsApplication.config.googleMaps.apiUrl+"&address=${address}"
def urlJSON = new URL(urlApi)
def geoCodeResultJSON = new JsonSlurper().parseText(urlJSON.getText())
return geoCodeResultJSON
}
}
class ClientListener extends AbstractPersistenceEventListener{
public boolean supportsEventType(Class<? extends ApplicationEvent> eventClass) {
switch(eventClass){
case [PreInsertEvent,
PreUpdateEvent,
PostInsertEvent,
PostUpdateEvent,
PostDeleteEvent]:
return true
default:
return false
}
}
protected void onPersistenceEvent(AbstractPersistenceEvent event) {
if(!(event.entityObject instanceof Client)){
return
}
switch(event.eventType) {
//GOOGLE MAPS geocode
case [EventType.PreInsert,EventType.PreUpdate]:
this.updateCoords(event.entityObject)
break
//OTHER STUFF (notifications, no changing inside)
case EventType.PostUpdate:
//....
}
}
private String composeAddress(Client cli){
def resul=[cli.address,cli.city,cli.country,cli.postalCode]
return resul.findAll{it}.join(",")
}
private void updateCoords(Client cli){
def fullAddress=this.composeAddress(cli)
if(fullAddress){
def coords=googleMapsService.geocode(fullAddress)
if (coords.status=="OK"){
//**IMPORTANT STUFF THESE TWO LINES RAISE AN EVENT
cli.lat=coords.results.geometry.location.lat[0]
cli.lng=coords.results.geometry.location.lng[0]
}
}
}
}
2。然后调用保存更新侦听器,并更新de对象
ClientGeoListener.onSaveOrUpdate(SaveOrUpdateEvent) line: 34
SessionImpl.fireSaveOrUpdate(SaveOrUpdateEvent) line: 685
SessionImpl.saveOrUpdate(String, Object) line: 677
SessionImpl.saveOrUpdate(Object) line: 673
3.连续地再次调用postUpdate grails listener:(
上次更新 最后,尝试只使用一个侦听器以保持简单。整个要点似乎是在插入之后执行hibernate“save update”侦听器,详细信息: 如果我禁用自定义侦听器而离开Hibernate侦听器(GEO),则会发生以下情况: 1。插入客户端(空白坐标)并调用saveupdate侦听器:
ClientGeoListener.onSaveOrUpdate(SaveOrUpdateEvent) line: 34
SessionImpl.fireSaveOrUpdate(SaveOrUpdateEvent) line: 685
SessionImpl.saveOrUpdate(String, Object) line: 677
2.坐标已更新,并且有一个更新
很抱歉进行了这么大的更新,Ideas???代替直接
lat
/lng
setter访问,也许可以尝试使用EntityAccess
。请参阅Grails内核中的示例。Grails在后台使用Hibernate。通常情况下,您不更新预更新
事件中的属性。您可以这样做,但如果如果不同时更新属性和基础的persistenentity
,可能会导致一些不希望的行为
该工作流解释了为什么您会获得两个更新:
lat
/lng
属性lat
/lng
的旧值lat
/lng
相同的值SaveOrUpdate
事件,而不是在更新之前使用
然而,由于您的目标是最大限度地减少不必要的API调用次数,因此在更新之前仍然值得使用
,因为在调用API之前手动检查实体是否存在污垢可能比其值得多。因此,您需要做的是,正如@Andrew建议的那样,确保更新属性以及实体,即:
event.entity.setProperty('lat', coords.results.geometry.location.lat[0])
event.entity.setProperty('lng', coords.results.geometry.location.lng[0])
cli.lat = coords.results.geometry.location.lat[0]
cli.lng = coords.results.geometry.location.lng[0]
更新:我的假设是,检查域对象是否脏可能很烦人,这实际上是基于我必须为NHibernate编写的代码。这当然是Grails,它应该简单如下:
if (event.entityObject.isDirty()) { /* Call API */ }
项目中是否有多个数据源?有一个可能与此相关的错误,请看:没有,只有一个数据源,我尝试使用cli。@lat为了跳过setter方法,但它也不起作用。:(更新了我的答案,其中有一个明显的遗漏。:)@ivo_èes如果不想让两个单独的类侦听,我假设您可以创建子类。不知道在没有看到代码的情况下还可以建议什么。顺便说一句,EventTriggeringInterceptor类所做的只是打开事件类型,然后使用event.getNativeEvent()将事件转换为休眠事件
所以,我想知道你是否可以退回到使用预更新
和/或预插入
然后从event.nativeEvent.entity
中获取实体。也许有人忘了在某个地方正确地分配引用。我将把问题简化为基本问题,并询问是否存在bug或其他问题saveupdate侦听器。谢谢您,:DUpdated link:仍然停留在grails 2.5上,并且存在此问题。该AutoTimestampListener仅用于单元测试。在集成测试或运行的应用程序中,未设置entityAccess:(