【问题标题】:Grails query to filter on association and only return matching entitiesGrails 查询以过滤关联并仅返回匹配的实体
【发布时间】:2012-08-21 15:35:49
【问题描述】:

我有以下 1 - M(单向)关系:

Customer (1) -> (M) Address

我正在尝试过滤包含特定文本的特定客户的地址,例如

def results = Customer.withCriteria {
    eq "id", 995L
    addresses {
        ilike 'description', '%text%'
    }
}

问题是这会返回客户,当我反过来访问“地址”时,它会为我提供完整的地址列表,而不是过滤后的地址列表。

我无法使用Address.withCriteria,因为我无法从条件查询中访问关联表。

我希望避免恢复为原始 SQL 查询,因为这意味着无法使用现有的大量功能以灵活且可重用的方式构建条件查询。

很想听听任何想法...

【问题讨论】:

    标签: sql grails grails-orm


    【解决方案1】:

    我相信 2.1 中不同行为的原因已记录在 here

    具体到这一点:

    以前用于跨关联的条件查询的默认 LEFT JOIN 现在是 INNER JOIN。

    IIRC,当您使用内部联接时,Hibernate 不会急切地加载关联。

    看起来您可以使用createAlias 指定外连接example here

    我对这个特定问题的经验来自于 NHibernate 的经验,因此我无法真正阐明如何使其正常工作。如果结果不正确,我会很乐意删除此答案。

    【讨论】:

      【解决方案2】:

      试试这个:

      def results = Customer.createCriteria().listDistinct() {
          eq('id', 995L)
          addresses {
              ilike('description', '%Z%')
          }
      }
      

      这将为您提供具有正确 id 和任何匹配地址的 Customer 对象,并且只有那些不匹配的地址。

      您还可以使用此查询(稍作修改)来获取所有具有匹配地址的客户:

      def results = Customer.createCriteria().listDistinct() {
          addresses {
              ilike('description', '%Z%')
          }
      }
      
      results.each {c->
          println "Customer " + c.name
          c.addresses.each {address->
              println "Address " + address.description
          }
      }
      

      编辑 以下是域类和我添加地址的方式:

      class Customer {
        String name
        static hasMany = [addresses: PostalAddress]
        static constraints = {
        }
      }
      class PostalAddress {
        String description
        static belongsTo = [customer: Customer]
        static constraints = {
        }
      }
      //added via Bootstrap for testing
      def init = { servletContext ->
          def custA = new Customer(name: 'A').save(failOnError: true)
          def custB = new Customer(name: 'B').save(failOnError: true)
          def custC = new Customer(name: 'C').save(failOnError: true)
      
          def add1 = new PostalAddress(description: 'Z1', customer: custA).save(failOnError: true)
          def add2 = new PostalAddress(description: 'Z2', customer: custA).save(failOnError: true)
          def add3 = new PostalAddress(description: 'Z3', customer: custA).save(failOnError: true)
          def add4 = new PostalAddress(description: 'W4', customer: custA).save(failOnError: true)
          def add5 = new PostalAddress(description: 'W5', customer: custA).save(failOnError: true)
          def add6 = new PostalAddress(description: 'W6', customer: custA).save(failOnError: true)
      
      }
      

      当我运行它时,我得到以下输出:

      Customer A
      Address Z3
      Address Z1
      Address Z2
      

      【讨论】:

      • 打印所有地址,而不是仅打印与查询匹配的地址。该查询确实返回了不同的客户,这很好。我正在寻找一种有效的方法来为客户找到匹配的地址,而无需在获取查询结果后遍历每个地址。​​
      • 您使用的是什么版本的 Grails?拥有 Customer 实例后,如何访问这些地址?当我模拟这个(使用 Grails 1.3.7 或 2.1)时,我将 6 个地址分配给我想用来测试的特定客户 - 其中只有 3 个在描述中具有匹配的文本。当我运行它时,只有这 3 个地址会返回。
      • 我使用的是 2.0.3,我也在 2.1.0 上尝试了上面的代码,我得到以下输出:Customer A Address Z1 Address W6 Address Z3 Address W5 Address Z2 Address W4
      • 我很抱歉 - 我在 2.1 中没有正确看待这一点。它的行为与您所说的完全一样 - 显示所有地址;在 1.3.7 中它只列出匹配的地址。如果我能弄清楚,我会更新。对不起!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-22
      • 1970-01-01
      • 1970-01-01
      • 2021-09-15
      • 1970-01-01
      相关资源
      最近更新 更多