2016-03-26 30 views
0

我已經在這樣的實體,使用GORM存儲在數據庫(I省略不相關的字段):GORM - 變化3個查詢到1(或至少2)

class Payment { 
    static hasMany = [paymentEntries: PaymentEntry] 
} 

class PaymentEntry { 
    static hasOne = [category: PaymentCategory] 
    static belongsTo = [payment: Payment] 
    static constraints = { 
    category(nullable: true) 
    } 
} 

class PaymentCategory { 
    static hasMany = [payments: PaymentEntry, rules: PaymentRule] 
    String name 
} 

因此,我們必須在頂部付款,從而可以有許多PaymentEntry,並且每個PaymentEntry可以屬於一個PaymentCategory。

我需要選擇Payments,它符合一些條件,但只有那些也具有屬於特定類別的PaymentEntries的Payments。目前,我這樣做是在3個查詢:

  1. 選擇類別,其適合的類別名稱的一部分,或者只是省略類別查詢(在我們希望無論他們的作品類別的所有付款這種情況下):

    private static List<PaymentCategory> getCategories(String category) { 
        def result = null 
        if (category != null && category.length() > 0) { 
         def c = PaymentCategory.createCriteria() 
    
         result = c { 
          ilike("name", "%${category}%") 
         } 
        } 
    
        result 
    } 
    
  2. 選擇PaymentEntries IDS,基於PaymentCategory:

    private static List<Long> paymentEntryIds(String category) { 
        def categories = getCategories(category) 
        def c = PaymentEntry.createCriteria() 
    
        def result = new ArrayList() 
    
        // If category is selected, but there is no matching category, return empty list 
        if (!categorySelectedButNoMatch(category, categories)) { 
         result = c { 
          if (category == null) { 
           isNull("category") 
          } else if (categories != null && categories.size() > 0) { 
           inList("category", categories) 
          } 
    
          projections { 
           property("id") 
          } 
         } 
        } 
    
        result 
    } 
    
  3. 最後選擇付款,僅限於包含特定Paymen的那些tEntries:

    def paymentEntriesIds = paymentEntryIds(selectedCategory) 
    
    def c = Payment.createCriteria() 
    
    def result = new ArrayList() 
    
    // If there are no payment entries matching category criteria, we return empty list anyway, so there 
    // is no need querying payments. 
    if (paymentEntriesIds.size() > 0) { 
        result = c { 
         paymentEntries { 
          inList("id", paymentEntriesIds) 
         } 
    
         if (importEntryId != null) { 
          eq("importEntry.id", importEntryId) 
         } 
         if (query != null) { 
          ilike("description", query) 
         } 
         // Omitted ordering and paging 
        } 
    } 
    
    result 
    

這工作,但它運行3個數據庫查詢。我很確定這個代碼可以更清晰,並且可以在更少的查詢中完成。歡迎所有關於如何改進它的想法。

+0

想一想使用連接。在付款標準 – user3718614

回答

0

您可以使用至少3種不同的方法:分離查詢,查詢的子查詢和HQL的子查詢。與標準DetachedQuery的

例子如下:

def subquery = new DetachedCriteria(PaymentCategory).build {   
    projections { 
     groupProperty 'id' 
    } 

    ilike("name", "%${category}%") 
} 

然後你就可以在另一個查詢中使用子查詢這樣:

return PaymentEntry.createCriteria().list {   
    category { 
     inList "id", subquery 
    } 
} 

我沒有測試它在你的域完全相同,這應該只是展示這個想法。請參閱GORM文檔的DetachedCriteria部分:https://grails.github.io/grails-doc/latest/guide/single.html#detachedCriteria

我們將它用於一些非常複雜的查詢。有時需要createAlias才能正確使用關聯。

+0

中如下所示:createAlias'paymentEntries','paymentEntries',JoinType.LEFT_OUTER_JOIN等等。如您對問題的第一條評論所述 - 如果可以使用JOIN完成,則它比子查詢更好。 – droggo

相關問題