2016-06-13 51 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