2016-06-13 49 views
0

在我的Grails Web应用程序,我有以下域类:Grails的3:使用的findAll与连接表

​​

现在我要实现的abillity过滤的1:N的关系一样的东西像国家地址(应该是动态的,这意味着用户可以自己添加不同的过滤器)。

完成此操作的最佳方法是什么?

  1. Customer对象中过滤集合?例如customer.addresses.findAll{...}
  2. 从数据库直接查询?我如何添加Customer<->Address关系的限制。 belongsToAddress域类是没有选择的,因为Address对象用于几个1:n的关系。例如Customer.findAll(...)
  3. 还有其他的选择吗?

回答

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 
} 

然后registe在每次添加新地址时将地址ID和countryCode添加到此域类中,我想您需要编写一些向后兼容的代码以将现有记录添加到此表以使其正常工作。

我留下了一条评论,然后将其删除,以便进一步扩展过滤发生的方式或过程。因为虽然你谈到的国家代码没有实际的代码来显示它是如何适合的。

我仍然认为这样简单的工作 //这只会做一个查找与地址的所有绑定对象绑定到这个客户。所以这个特定客户

protected def getCustomAddress(String countryCode) { 
    return addresses.findAll{it.code==countryCode} 
} 

其他深远的思路的的hasMany关系要素中的发现可能是这样的

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) 
+0

约束如何帮助我实现过滤功能(例如获取美国客户的所有地址)? 'checkAddress'只验证'addresses'和'checkAddress2'' findAllByCustomer'中不超过2个对象是不可能的,因为'Address'没有'customer'字段 – Andreas

+0

obj?.addresses.findAll {it.country = ='美国'}?可能。 @Andreas – Vahid

+0

这实际上是一个问题,这样做的缺点是集合的所有对象(在本例中为地址)从数据库中获取 – Andreas