GORM - 将3个查询更改为1(或至少2个)

时间:2016-03-26 10:01:58

标签: grails gorm

我有这样的实体,使用GORM存储在数据库中(我省略了不相关的字段):

public class JsonParser {
    public static List<DrawerItem> parseFeed(String content) {
        try {
            JSONObject jsonRootObject = new JSONObject(content);
            JSONArray jsonArray = jsonRootObject.optJSONArray("Rows");
            List<DrawerItem> draweritemList = new ArrayList<>();
            for (int i = 0; i < jsonArray.length(); i++) {
                JSONObject obj = jsonArray.getJSONObject(i);
                DrawerItem draweritem = new DrawerItem();

                draweritem.setId(obj.getString("Id"));
                draweritem.setTitle(obj.getString("Title"));
                draweritemList.add(draweritem);
            }
            return draweritemList;
        } catch (JSONException e) {
            e.printStackTrace();
            return null;
        }
    }
}

所以我们在顶部有付款,可以有很多PaymentEnies,每个PaymentEntry都可以属于一个PaymentCategory。

我需要选择符合某些条件的付款,但只需选择也属于特定类别的付款条款的付款。目前我在3个查询中执行此操作:

  1. 选择适合类别名称部分的类别,或者只是省略类别查询(在这种情况下,我们希望所有付款,无论其条目类别如何):

    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
    }
    
  2. 根据PaymentCategory选择PaymentEntries ID:

    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
    }
    
  3. 最后选择付款,仅限于包含特定PaymentEntries的付款:

    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
    }
    
  4. 这样可行,但它会对数据库运行3次查询。我非常确定这段代码可以更干净,而且可以在更少的查询中完成。关于如何改进它的所有想法都是受欢迎的。

1 个答案:

答案 0 :(得分: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需要正确使用关联。