在我的Grails webapp中,我有以下域类:
DogList->
现在我想实现abillity来过滤像国家这样的地址的1:n关系(应该是动态的,这意味着用户可以自己添加不同的过滤器)。
实现这一目标的最佳方法是什么?
class Customer {
static hasMany = [
addresses: Address
]
static mapping = {
addresses (cascade: "all-delete-orphan", joinTable: [name: "bs_core_customer_addresses"])
}
}
class Address {
...
}
对象过滤集合?例如Customer
customer.addresses.findAll{...}
关系的限制。 Customer<->Address
域类中的belongsTo
是没有选项的,因为Address
对象用于几个1:n关系。例如Address
答案 0 :(得分:0)
你应该能够逃脱
static constraints = {
addresses(validator: checkAddress)
}
// This is a static method which is used for validation
// and can be used for when inserting a record to check how many
// existing addresses exist for the end user that has countryCode of US
// This is directly bound to all the object the user and will
// will not be searching the entire DB (A local find limited to user records)
static def checkAddress={val,obj,errors->
if (!obj?.addresses.findAll{it.countryCode=='US'}?.size() >= 2) {
return errors.rejectValue('adress','exceeds limit')
}
}
以上内容应该是自我解释的,但现在已经阅读了几篇文章,我认为我对你想要实现的目标有了更好的理解,并且可能有几种不同的方法。那么让我们来探讨一下:
使用HQL查询,您可以将其更改为其他方法,我更喜欢HQL。
class Customer {
def userService
//UserAddress does not have setter transients not essential
static transients = ['userAddress','userService']
//This is a protected function that will return an address
// object given a countryCode
// Execute like this:
// Customer cm = Customer.get(customer.id as Long)
//Address usa = cm.getCountry('US')
protected Address getUserAddress(String countryCode) {
return userService.findAddress(countryCode, this.id)
}
}
现在服务但实际上你不需要在域类中执行,除非有其他需要,为了显示等,你总是可以在控制器调用中调用这种服务来呈现以用于显示目的
class UserSerice {
// This should return the entire address object back to the domain class
// that called it and will be quicker more efficient than findAll
Address findAddress(String countryCode, Long customerId) {
String query="""
select address from Address a
where a.id :id and countryCode = :code
"""
def inputParams=[code:countryCode, id:customerId]
return Address.executeQuery(query,inputParams,[readOnly:true,timeout:15])
}
另一种方法可能是第3个表,它会根据添加的每个地址进行更新,以便快速查找:
class Customer {
static hasMany = [
addresses: Address
//probably don't even need this
//, userCountries:UserCountries
]
}
Class UserCountries {
// register customer
Customer customer
String CountryCode
//maybe address object or Long addressId - depending on if how plain you wanted this to be
Address address
}
每次添加新地址时,都会将地址ID和countryCode注册到此域类,我猜您需要编写一些向后兼容的代码,以便将现有记录添加到此表中,以使其正常工作。
我发表评论然后将其删除,以便进一步了解过滤的内容或方式。因为虽然你谈到countryCode,但没有实际的代码来展示它是如何适应的。
我仍然认为这样的事情很简单 //这只会使用绑定到此客户的所有绑定地址对象进行查找。所以在这个特定客户的hasMany关系元素中查找
protected def getCustomAddress(String countryCode) {
return addresses.findAll{it.code==countryCode}
}
其他很远的想法可能是这样的
class Customer {
String _bindAddress
List bindAddress=[]
static transients = [ 'bindAddress' ]
static constraints = {
_bindAddress(nullable:true)
}
//you store a flat CSV as _bindAddress
//you need to work out your own logic to ammend to existing CSV each time address is added
// you will also update _bindAddress of this domainClass each time customer gets a hasMany address added
// so no need for setBindAddress
// void setBindAddress(String b) {
// bindAddress=b.split(',')
// }
//Inorder to set a list back to flat file
//pass in list object
void setBindAddress(List bindAddress) {
_bindAddress=bindAddress.join(',')
/for 1 element this captures better
//_bindAddress=bindAddress.tokenize(',').collect{it}
}
//This is now your object as a list that you can query for what you are querying.
List getBindAdress() {
return _bindAddress.split(',')
}
}
如果您的实际csv列表包含'COUNTRY_CODE-ADDRESS_ID'列表,那么您可以像这样查询
def found = customer.bindAddress.find{it.startsWith('US-')}
Address usaAddress= Address.get(found.split('-')[1] as Long)
//Slightly longer explaining above:
def found = customer.bindAddress.find{it.startsWith('US-')}
def record = found.split('-')
String countryCode=record[0]
Long addressId=record[1] as Long
Address usaAddress= Address.get(addressId)