{"id":885,"date":"2011-01-02T14:24:31","date_gmt":"2011-01-02T17:24:31","guid":{"rendered":"https:\/\/devkico.itexto.com.br\/?p=885"},"modified":"2011-01-02T14:34:54","modified_gmt":"2011-01-02T17:34:54","slug":"grails-entendendo-a-busca-por-criterios-criterias","status":"publish","type":"post","link":"https:\/\/devkico.itexto.com.br\/?p=885","title":{"rendered":"Grails: entendendo a busca por crit\u00e9rios (criterias)"},"content":{"rendered":"<p><a href=\"https:\/\/devkico.itexto.com.br\/wp-content\/uploads\/2010\/02\/grails_logo.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignleft size-full wp-image-604\" style=\"margin: 10px;\" title=\"grails_logo\" src=\"https:\/\/devkico.itexto.com.br\/wp-content\/uploads\/2010\/02\/grails_logo.png\" alt=\"\" width=\"163\" height=\"43\" \/><\/a>Um dos recursos mais mal compreendidos do Grails s\u00e3o as criterias (ser\u00e1 que posso falar &#8220;crit\u00e9rias&#8221; no plural?). O objetivo deste post \u00e9 ir al\u00e9m do feij\u00e3o com arroz que encontramos na documenta\u00e7\u00e3o oficial. Espero que assim algumas das d\u00favidas mais comuns que escuto a respeito deste recurso sejam resolvidas.<\/p>\n<p>Vamos tratar de uma situa\u00e7\u00e3o t\u00edpica: uma \u00e1rvore geneal\u00f3gica bem idiota, representada pelas tr\u00eas classes de dom\u00ednio abaixo:<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\nclass Pai {\r\n\r\nString nome\r\n\r\nString sobrenome\r\n\r\nstatic hasMany = &#x5B;filhos:Filho]\r\n\r\nString toString() {this.nome}\r\n\r\n}\r\n\r\nclass Filho {\r\n\r\nString nome\r\n\r\nString sobrenome\r\n\r\nInteger idade\r\n\r\nstatic belongsTo = &#x5B;pai:Pai]\r\n\r\nstatic hasMany = &#x5B;filhos:Neto]\r\n\r\nString toString() {this.nome}\r\n\r\n}\r\n\r\nclass Neto {\r\n\r\nString nome\r\n\r\nString sobrenome\r\n\r\nString status\r\n\r\nstatic belongsTo = &#x5B;pai:Filho]\r\n\r\nString toString() {this.nome}\r\n\r\n}\r\n<\/pre>\n<p>Com base nesta estrutura de classes, criei uma hierarquia que representei no grafo abaixo, que servir\u00e1 para que possamos trabalhar neste post.<\/p>\n<p><a href=\"https:\/\/devkico.itexto.com.br\/wp-content\/uploads\/2011\/01\/parentesco2.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-891\" title=\"parentesco\" src=\"https:\/\/devkico.itexto.com.br\/wp-content\/uploads\/2011\/01\/parentesco2.png\" alt=\"\" width=\"540\" height=\"123\" srcset=\"https:\/\/devkico.itexto.com.br\/wp-content\/uploads\/2011\/01\/parentesco2.png 540w, https:\/\/devkico.itexto.com.br\/wp-content\/uploads\/2011\/01\/parentesco2-300x68.png 300w\" sizes=\"(max-width: 540px) 100vw, 540px\" \/><\/a><\/p>\n<h2>T\u00e1: mas o que \u00e9 uma criteria?<\/h2>\n<p>Grails nos oferece tr\u00eas ferramentas para que possamos fazer consultas em um banco de dados: finders din\u00e2micos, HQL (Hibernate Query Language) e criterias. A busca por crit\u00e9rios do Grails \u00e9 na realidade uma abstra\u00e7\u00e3o do mesmo recurso oferecido pelo <a href=\"http:\/\/docs.jboss.org\/hibernate\/core\/3.6\/reference\/pt-BR\/html\/querycriteria.html\" target=\"_blank\">Hibernate<\/a>. A diferen\u00e7a \u00e9 que temos aqui uma vers\u00e3o mais &#8220;groovy&#8221;, uma DSL baseada nos\u00a0<a href=\"http:\/\/groovy.codehaus.org\/Builders\" target=\"_blank\">builders<\/a> do Groovy.<\/p>\n<h3>Por que usar criterias se j\u00e1 tenho os lindos finders din\u00e2micos?<\/h3>\n<p>Os finders din\u00e2micos s\u00e3o feitos para consultas simples que envolvam algo entre uma e tr\u00eas condi\u00e7\u00f5es no m\u00e1ximo (minha opini\u00e3o). Se for necess\u00e1rio buscar os registros levando como base o atributo de um atributo composto da sua classe, esque\u00e7a os finders din\u00e2micos. Exerc\u00edcio pra voc\u00ea: retorne usando finders din\u00e2micos todos os netos de &#8220;Joe Lonely&#8221; em nosso exemplo.<\/p>\n<h3>Por que usar criterias se j\u00e1 tenho HQL?<\/h3>\n<p>A HQL j\u00e1 nos permite criar consultas BEM mais avan\u00e7adas que os finders din\u00e2micos e com mesmo n\u00edvel de complexidade que as crit\u00e9rias. Al\u00e9m disto, tanto os finders din\u00e2micos quanto as crit\u00e9rias geram, no frigir dos ovos, HQL. Sendo assim, porque usar uma camada superior se posso ir direto ao HQL? Simples: porque a concatena\u00e7\u00e3o de strings uma hora ou outra aparece quando trabalhamos com consultas REALMENTE complexas usando HQL.<\/p>\n<p>E acredite: concatena\u00e7\u00e3o de strings pode n\u00e3o gerar trag\u00e9dias no primeiro dia, mas quando voc\u00ea menos esperar elas vir\u00e3o atr\u00e1s de voc\u00ea (elas s\u00e3o terr\u00edveis!).<\/p>\n<p><strong>O B\u00e1sico<\/strong><\/p>\n<p>Toda classe de dom\u00ednio do Grails possui injetada a fun\u00e7\u00e3o <em>createCriteria<\/em>, que retorna um objeto do tipo <a href=\"http:\/\/www.grails.org\/Hibernate+Criteria+Builder\" target=\"_blank\">grails.gorm.HibernateCriteriaBuilder<\/a>. Esta classe, por sua vez, possui uma fun\u00e7\u00e3o que ser\u00e1 usada em 99% dos casos: a fun\u00e7\u00e3o <em>list<\/em>.<\/p>\n<p>Na pr\u00e1tica, caso desejemos listar todos os netos do nosso exemplo, poder\u00edamos escrever o c\u00f3digo abaixo:<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\n\r\ndef criteria = Neto.createCriteria()\r\ncriteria.list {}\r\n\r\n<\/pre>\n<p>O m\u00e9todo list sempre recebe como par\u00e2metro uma estrutura hierarquica. Neste caso, como foi passada uma estrutura vazia, todos os resultados s\u00e3o retornados. Caso fosse de nosso interesse retornar todos os netos cujo nome comece com &#8220;Pentelho&#8221;, escreveriamos o c\u00f3digo abaixo:<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\n\r\ndef criteria = Neto.createCriteria()\r\ncriteria.list {\r\nlike(&quot;nome&quot;, &quot;Pentelho%&quot;)\r\n}\r\n\r\n<\/pre>\n<p>Seriam retornados os netos &#8220;Pentelho Lonely Joe&#8221; e &#8220;Pentelhox Lonely JOe&#8221;. No interior desta estrutura incluimos as express\u00f5es que ir\u00e3o compor a nossa consulta.<\/p>\n<p><strong>Dica:<\/strong> sempre pense na estrutura passada como um documento XML. Assim fica BEM mais f\u00e1cil compreender o que est\u00e1 sendo feito.<\/p>\n<p>\u00c9 poss\u00edvel tamb\u00e9m usar os operadores l\u00f3gicos or, and e not. No exemplo abaixo listar\u00edamos todos os netos cujo nome comece com &#8220;Lori&#8221; ou &#8220;Pentelho&#8221;.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\n\r\ndef criteria = Neto.createCriteria()\r\ncriteria {\r\nor {\r\nlike(&quot;nome&quot;, &quot;Pentelho%&quot;)\r\nlike(&quot;nome&quot;, &quot;Lori%&quot;)\r\n\r\n}\r\n}\r\n\r\n<\/pre>\n<p>Observe que neste exemplo n\u00e3o usei a fun\u00e7\u00e3o list. Se passarmos diretamente o builder para o objeto criteria, usando a invoca\u00e7\u00e3o din\u00e2mica de m\u00e9todos do Groovy, este j\u00e1 detecta que estamos na realidade chamando <em>list<\/em>. Trata-se apenas de uma conveniencia provida pelo framework.<\/p>\n<p>A listagem completa de operadores suportados na busca por crit\u00e9rios pode ser obtida neste link: <a href=\"http:\/\/grails.org\/doc\/latest\/ref\/Domain%20Classes\/createCriteria.html\" target=\"_blank\">http:\/\/grails.org\/doc\/latest\/ref\/Domain%20Classes\/createCriteria.html<\/a><\/p>\n<h2>Operadores l\u00f3gicos<\/h2>\n<p>As crit\u00e9rias brilham quando precisamos usar express\u00f5es que envolvam os operadores l\u00f3gicos <strong>and<\/strong> e, principalmente, o <strong>or<\/strong>. A melhor maneira de expor a sua superioridade \u00e9 expor uma situa\u00e7\u00e3o na qual o uso destes operadores da merda: finders din\u00e2micos.<\/p>\n<p>Tenha como exemplo a consulta abaixo:<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\n\r\nNeto.findAllByNomeLikeOrNomeLikeAndStatus(&quot;Pentelho%&quot;, &quot;Lori%&quot;, &quot;Idiota&quot;)\r\n\r\n<\/pre>\n<p>Que consulta exatamente temos aqui?<\/p>\n<ul>\n<li>(nome like &#8220;Pentelho%&#8221; ou nome like(&#8220;Lori%&#8221;) e (status = &#8220;Idiota&#8221;) ?<\/li>\n<li>(nome like &#8220;Pentelho%&#8221;) ou (nome like(&#8220;Lori%&#8221;) e (status = &#8220;Idiota&#8221;) ?<\/li>\n<\/ul>\n<p>Na realidade ser\u00e1 a segunda op\u00e7\u00e3o. Por\u00e9m h\u00e1 espa\u00e7o para d\u00favida. E se este existe, o que voc\u1ebd faz? Voc\u00ea foge dele e usa a busca por crit\u00e9rios ora! Veja como consulta similar pode ser escrita de maneira MUITO mais clara:<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\n\r\ndef criteria = Neto.createCriteria()\r\ncriteria {\r\n or {\r\n like(&quot;nome&quot;, &quot;Pentelho%&quot;)\r\n like(&quot;nome&quot;, &quot;Lori%&quot;)\r\n }\r\n eq(&quot;status&quot;, &quot;Idiota&quot;)\r\n\r\n}\r\n<\/pre>\n<p>O operador <strong>or<\/strong> recebe como par\u00e2metro um novo builder, aonde \u00e9 poss\u00edvel incluir quantas opera\u00e7\u00f5es, comparadores ou builders sejam necess\u00e1rios. Como resultado, t\u00eam-se um c\u00f3digo ordens de magnitude mais f\u00e1cil de entender e n\u00e3o sujeito a erros de interpreta\u00e7\u00e3o por parte do programador.<\/p>\n<p>Nota importante: por default, dentro de uma busca por crit\u00e9rios temos o operador <strong>and<\/strong>. Sendo assim, a consulta abaixo:<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\ndef criteria = Neto.createCriteria()\r\ncriteria {\r\n     like(&quot;nome&quot;, &quot;Pentelho%&quot;)\r\n     eq(&quot;status&quot;, &quot;Idiota&quot;)\r\n}\r\n<\/pre>\n<p>Equivale \u00e0 consulta<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\ndef criteria = Neto.createCriteria()\r\ncriteria {\r\n     and {\r\n         like(&quot;nome&quot;, &quot;Pentelho%&quot;)\r\n         eq(&quot;status&quot;, &quot;Idiota&quot;)\r\n     }\r\n}\r\n<\/pre>\n<p>S\u00f3 pra expor o funcionamento por tr\u00e1s dos panos, quando usamos os blocos <strong>or<\/strong> ou <strong>and<\/strong>, estamos na realidade criando novas inst\u00e2ncias das classes <em>Conjunction<\/em> e <em>Disjunction, <\/em>derivadas de org.hibernate.criterion.Junction. Pra quem j\u00e1 trabalhou com Hibernate, fica n\u00edtido o fato de novamente aqui n\u00e3o haver NADA de novo (o que \u00e9 \u00f3timo!) :)<\/p>\n<h2>Criterias din\u00e2micas<\/h2>\n<p>Como mencionei acima, um dos objetivos da busca por crit\u00e9rios \u00e9 evitar a concatena\u00e7\u00e3o de strings na constru\u00e7\u00e3o de consultas. Um recurso muito pouco documentado das crit\u00e9rias \u00e9 a possibilidade de constru\u00ed-las em tempo de execu\u00e7\u00e3o.<\/p>\n<p>O c\u00f3digo abaixo exp\u00f5e um exemplo:<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\n\r\ndef valorNumerico = 1\r\ndef tipoBusca = &quot;sobrenome&quot;\r\ndef valorSobrenome = &quot;Lonely&quot;\r\n\r\ndef criteria = Pai.createCriteria()\r\ncriteria {\r\nif (valorNumerico == 1) {\r\neq(&quot;nome&quot;, &quot;Joe Lonely&quot;)\r\n} else {\r\nlike(&quot;nome&quot;, &quot;%o%&quot;)\r\n}\r\n\r\nif (tipoBusca)\r\neq(&quot;sobrenome&quot;, valorSobrenome)\r\n}\r\n\r\n<\/pre>\n<p>Olha que legal: voc\u00ea pode incluir instru\u00e7\u00f5es condicionais como if, else e switch no interior do builder. Assim, este pode ser constru\u00eddo em tempo de execu\u00e7\u00e3o. \u00c9 um recurso poderos\u00edssimo e, infelizmente, pouco exposto em exemplos. Fica como exerc\u00edcio implementar o mesmo c\u00f3digo acima usando HQL. Produzir algo similar com finders din\u00e2micos \u00e9 imposs\u00edvel (se voc\u00ea conseguir, poste nos coment\u00e1rios aqui ok?).<\/p>\n<h2>O atributo de um atributo<\/h2>\n<p>\u00c9 muito comum situa\u00e7\u00f5es nas quais \u00e9 necess\u00e1rio buscar registros com base no atributo de um dos seus atributos compostos. Imagine que queiramos buscar todos os filhos de &#8220;Joelinho Lonely&#8221; cujo nome comece com &#8220;Pentelho&#8221;. Simples: basta adicionar, ao inv\u00e9s de uma opera\u00e7\u00e3o de compara\u00e7\u00e3o, o nome do pr\u00f3prio atributo na criteria, tal como no c\u00f3digo abaixo:<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\n\r\ndef criteria = Neto.createCriteria()\r\ncriteria {\r\npai {\r\neq(&quot;nome&quot;, &quot;Joelinho Lonely&quot;)\r\n}\r\nlike(&quot;nome&quot;, &quot;Pentelho%&quot;)\r\n}\r\n\r\n<\/pre>\n<p>Observe que interessante: estamos incluindo um builder dentro de outro. No caso, um dos n\u00f3s do nosso builder \u00e9 o atributo &#8220;pai&#8221; da classe &#8220;Neto&#8221;. Em seu interior, podemos incluir quantas express\u00f5es quisermos, inclusive outros builders. Pra complicar um pouco mais a situa\u00e7\u00e3o, vamos buscar todos os netos cujo nome comece com &#8220;Pentelho&#8221;, sejam filhos de &#8220;Joelinho Lonely&#8221; e netos do bom e velho &#8220;Joe Lonely&#8221;.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\n\r\ndef criteria = Neto.createCriteria()\r\ncriteria {\r\n pai {\r\n eq(&quot;nome&quot;, &quot;Joelinho Lonely&quot;)\r\npai {\r\neq(&quot;nome&quot;, &quot;Joe Lonely&quot;)\r\n}\r\n }\r\n like(&quot;nome&quot;, &quot;Pentelho%&quot;)\r\n}\r\n\r\n<\/pre>\n<h2>Buscando um pai pelos filhos<\/h2>\n<p>Ok, agora vamos supor que queiramos buscar todos os registros da classe &#8220;Filho&#8221; a partir dos filhos que possuem. Retornando \u00e0 implementa\u00e7\u00e3o da classe filho, vemos que h\u00e1 um atributo filhos nesta. Haveria como, por exemplo, buscar todos os registros de Filho que tenham gerado netos cujo nome comece com &#8220;Pentelho&#8221;? Yeap! Veja o c\u00f3digo abaixo:<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\ndef criterio = Filho.createCriteria()\r\n\r\ncriterio {\r\n\r\nfilhos {\r\n\r\nlike(&quot;nome&quot;, &quot;Pente%&quot;)\r\n\r\n}\r\n\r\n}\r\n\r\n<\/pre>\n<h2>Concluindo<\/h2>\n<p>Espero que com estas duas caracter\u00edsticas pouco conhecidas das crit\u00e9rias eu tenha ajudado a elucidar algumas d\u00favidas que costumam aparecer aos iniciantes em Grails. Para quem j\u00e1 trabalhou com Hibernate, fica n\u00edtido que estamos lidando exatamente com o mesmo recurso, por\u00e9m com uma roupagem mais leg\u00edvel.<\/p>\n<p>Para de fato entender a fundo este recurso, recomendo a leitura dos seguintes links:<\/p>\n<div style=\"padding: 2.0em;\"><a href=\"http:\/\/groovy.codehaus.org\/Builders\">Groovy Builders<\/a> &#8211; compreender os builders do Groovy ajuda muito a entender outros recursos presentes no Grails como por exemplo as constraints (ser\u00e1 meu pr\u00f3ximo post, aguardem)<\/p>\n<p><a href=\"http:\/\/www.grails.org\/Hibernate+Criteria+Builder\" target=\"_blank\">Hibernate Criteria<\/a> &#8211; como funcionam as crit\u00e9rias do Hibernate, que \u00e9 o pano de fundo deste recurso.<\/p>\n<p><a href=\"https:\/\/github.com\/grails\/grails-core\/blob\/master\/src\/java\/grails\/orm\/HibernateCriteriaBuilder.java\" target=\"_blank\">org.grails.HibernateCriteriaBuilder<\/a> &#8211; O c\u00f3digo fonte por tr\u00e1s do funcionamento da busca por crit\u00e9rios<\/p>\n<\/div>\n<p>S\u00f3 pra lembrar, voc\u00ea deve usar as buscas por crit\u00e9rios se um dos casos abaixo aparecer:<\/p>\n<ul>\n<li>A consulta envolve mais de duas ou tr\u00eas condi\u00e7\u00f5es<\/li>\n<li>\u00c9 necess\u00e1ria a inclus\u00e3o de operadores l\u00f3gicos como or, and e not<\/li>\n<li>Voc\u00ea deseja construir a consulta em tempo de execu\u00e7\u00e3o e voc\u00ea quer evitar concatena\u00e7\u00e3o de strings<\/li>\n<li>\u00c9 necess\u00e1rio aumentar a legibilidade do c\u00f3digo de suas consultas<\/li>\n<\/ul>\n<p>Quanto \u00e0 \u00faltima raz\u00e3o, pe\u00e7o perd\u00e3o ao leitor. Infelizmente, o renderizador de c\u00f3digo deste blog \u00e9 <strong>muito<\/strong> primitivo e n\u00e3o exp\u00f5e corretamente a indenta\u00e7\u00e3o (mas pretendo resolver isto em breve).<\/p>\n<p>Bom, at\u00e9 a pr\u00f3xima ent\u00e3o. Meu pr\u00f3ximo assunto ser\u00e1 ou um detalhamento maior sobre a valida\u00e7\u00e3o em Grails ou algum novo experimento envolvendo desenvolvimento de jogos usando HTML5 (ou ser\u00e3o os dois de uma vez?)<\/p>\n<p>Grande abra\u00e7o!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Um dos recursos mais mal compreendidos do Grails s\u00e3o as criterias (ser\u00e1 que posso falar &#8220;crit\u00e9rias&#8221; no plural?). O objetivo deste post \u00e9 ir al\u00e9m do feij\u00e3o com arroz que encontramos na documenta\u00e7\u00e3o oficial. Espero que assim algumas das d\u00favidas mais comuns que escuto a respeito deste recurso sejam resolvidas. Vamos tratar de uma situa\u00e7\u00e3o [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_coblocks_attr":"","_coblocks_dimensions":"","_coblocks_responsive_height":"","_coblocks_accordion_ie_support":"","site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-gradient":""}},"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[3,30,5],"tags":[],"class_list":["post-885","post","type-post","status-publish","format-standard","hentry","category-grails","category-grails-guia-rapido-e-indireto","category-groovy"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v22.8 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Grails: entendendo a busca por crit\u00e9rios (criterias) - \/dev\/Kico<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/devkico.itexto.com.br\/?p=885\" \/>\n<meta property=\"og:locale\" content=\"pt_BR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Grails: entendendo a busca por crit\u00e9rios (criterias) - \/dev\/Kico\" \/>\n<meta property=\"og:description\" content=\"Um dos recursos mais mal compreendidos do Grails s\u00e3o as criterias (ser\u00e1 que posso falar &#8220;crit\u00e9rias&#8221; no plural?). O objetivo deste post \u00e9 ir al\u00e9m do feij\u00e3o com arroz que encontramos na documenta\u00e7\u00e3o oficial. Espero que assim algumas das d\u00favidas mais comuns que escuto a respeito deste recurso sejam resolvidas. Vamos tratar de uma situa\u00e7\u00e3o [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/devkico.itexto.com.br\/?p=885\" \/>\n<meta property=\"og:site_name\" content=\"\/dev\/Kico\" \/>\n<meta property=\"article:published_time\" content=\"2011-01-02T17:24:31+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2011-01-02T17:34:54+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/www.itexto.net\/devkico\/wp-content\/uploads\/2010\/02\/grails_logo.png\" \/>\n<meta name=\"author\" content=\"Kico (Henrique Lobo Weissmann)\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@loboweissmann\" \/>\n<meta name=\"twitter:label1\" content=\"Escrito por\" \/>\n\t<meta name=\"twitter:data1\" content=\"Kico (Henrique Lobo Weissmann)\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. tempo de leitura\" \/>\n\t<meta name=\"twitter:data2\" content=\"9 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/devkico.itexto.com.br\/?p=885\",\"url\":\"https:\/\/devkico.itexto.com.br\/?p=885\",\"name\":\"Grails: entendendo a busca por crit\u00e9rios (criterias) - \/dev\/Kico\",\"isPartOf\":{\"@id\":\"https:\/\/devkico.itexto.com.br\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/devkico.itexto.com.br\/?p=885#primaryimage\"},\"image\":{\"@id\":\"https:\/\/devkico.itexto.com.br\/?p=885#primaryimage\"},\"thumbnailUrl\":\"https:\/\/devkico.itexto.com.br\/wp-content\/uploads\/2010\/02\/grails_logo.png\",\"datePublished\":\"2011-01-02T17:24:31+00:00\",\"dateModified\":\"2011-01-02T17:34:54+00:00\",\"author\":{\"@id\":\"https:\/\/devkico.itexto.com.br\/#\/schema\/person\/502ab8892631bb005d6da2269fe5a3a7\"},\"breadcrumb\":{\"@id\":\"https:\/\/devkico.itexto.com.br\/?p=885#breadcrumb\"},\"inLanguage\":\"pt-BR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/devkico.itexto.com.br\/?p=885\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@id\":\"https:\/\/devkico.itexto.com.br\/?p=885#primaryimage\",\"url\":\"https:\/\/devkico.itexto.com.br\/wp-content\/uploads\/2010\/02\/grails_logo.png\",\"contentUrl\":\"https:\/\/devkico.itexto.com.br\/wp-content\/uploads\/2010\/02\/grails_logo.png\",\"width\":\"163\",\"height\":\"43\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/devkico.itexto.com.br\/?p=885#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/devkico.itexto.com.br\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Grails: entendendo a busca por crit\u00e9rios (criterias)\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/devkico.itexto.com.br\/#website\",\"url\":\"https:\/\/devkico.itexto.com.br\/\",\"name\":\"\/dev\/Kico\",\"description\":\"Desenvolvendo software\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/devkico.itexto.com.br\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"pt-BR\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/devkico.itexto.com.br\/#\/schema\/person\/502ab8892631bb005d6da2269fe5a3a7\",\"name\":\"Kico (Henrique Lobo Weissmann)\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@id\":\"https:\/\/devkico.itexto.com.br\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/dd6973d86a689bc63122b2e603f25be3?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/dd6973d86a689bc63122b2e603f25be3?s=96&d=mm&r=g\",\"caption\":\"Kico (Henrique Lobo Weissmann)\"},\"sameAs\":[\"https:\/\/x.com\/loboweissmann\"],\"url\":\"https:\/\/devkico.itexto.com.br\/?author=1\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Grails: entendendo a busca por crit\u00e9rios (criterias) - \/dev\/Kico","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/devkico.itexto.com.br\/?p=885","og_locale":"pt_BR","og_type":"article","og_title":"Grails: entendendo a busca por crit\u00e9rios (criterias) - \/dev\/Kico","og_description":"Um dos recursos mais mal compreendidos do Grails s\u00e3o as criterias (ser\u00e1 que posso falar &#8220;crit\u00e9rias&#8221; no plural?). O objetivo deste post \u00e9 ir al\u00e9m do feij\u00e3o com arroz que encontramos na documenta\u00e7\u00e3o oficial. Espero que assim algumas das d\u00favidas mais comuns que escuto a respeito deste recurso sejam resolvidas. Vamos tratar de uma situa\u00e7\u00e3o [&hellip;]","og_url":"https:\/\/devkico.itexto.com.br\/?p=885","og_site_name":"\/dev\/Kico","article_published_time":"2011-01-02T17:24:31+00:00","article_modified_time":"2011-01-02T17:34:54+00:00","og_image":[{"url":"http:\/\/www.itexto.net\/devkico\/wp-content\/uploads\/2010\/02\/grails_logo.png"}],"author":"Kico (Henrique Lobo Weissmann)","twitter_card":"summary_large_image","twitter_creator":"@loboweissmann","twitter_misc":{"Escrito por":"Kico (Henrique Lobo Weissmann)","Est. tempo de leitura":"9 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/devkico.itexto.com.br\/?p=885","url":"https:\/\/devkico.itexto.com.br\/?p=885","name":"Grails: entendendo a busca por crit\u00e9rios (criterias) - \/dev\/Kico","isPartOf":{"@id":"https:\/\/devkico.itexto.com.br\/#website"},"primaryImageOfPage":{"@id":"https:\/\/devkico.itexto.com.br\/?p=885#primaryimage"},"image":{"@id":"https:\/\/devkico.itexto.com.br\/?p=885#primaryimage"},"thumbnailUrl":"https:\/\/devkico.itexto.com.br\/wp-content\/uploads\/2010\/02\/grails_logo.png","datePublished":"2011-01-02T17:24:31+00:00","dateModified":"2011-01-02T17:34:54+00:00","author":{"@id":"https:\/\/devkico.itexto.com.br\/#\/schema\/person\/502ab8892631bb005d6da2269fe5a3a7"},"breadcrumb":{"@id":"https:\/\/devkico.itexto.com.br\/?p=885#breadcrumb"},"inLanguage":"pt-BR","potentialAction":[{"@type":"ReadAction","target":["https:\/\/devkico.itexto.com.br\/?p=885"]}]},{"@type":"ImageObject","inLanguage":"pt-BR","@id":"https:\/\/devkico.itexto.com.br\/?p=885#primaryimage","url":"https:\/\/devkico.itexto.com.br\/wp-content\/uploads\/2010\/02\/grails_logo.png","contentUrl":"https:\/\/devkico.itexto.com.br\/wp-content\/uploads\/2010\/02\/grails_logo.png","width":"163","height":"43"},{"@type":"BreadcrumbList","@id":"https:\/\/devkico.itexto.com.br\/?p=885#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/devkico.itexto.com.br\/"},{"@type":"ListItem","position":2,"name":"Grails: entendendo a busca por crit\u00e9rios (criterias)"}]},{"@type":"WebSite","@id":"https:\/\/devkico.itexto.com.br\/#website","url":"https:\/\/devkico.itexto.com.br\/","name":"\/dev\/Kico","description":"Desenvolvendo software","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/devkico.itexto.com.br\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"pt-BR"},{"@type":"Person","@id":"https:\/\/devkico.itexto.com.br\/#\/schema\/person\/502ab8892631bb005d6da2269fe5a3a7","name":"Kico (Henrique Lobo Weissmann)","image":{"@type":"ImageObject","inLanguage":"pt-BR","@id":"https:\/\/devkico.itexto.com.br\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/dd6973d86a689bc63122b2e603f25be3?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/dd6973d86a689bc63122b2e603f25be3?s=96&d=mm&r=g","caption":"Kico (Henrique Lobo Weissmann)"},"sameAs":["https:\/\/x.com\/loboweissmann"],"url":"https:\/\/devkico.itexto.com.br\/?author=1"}]}},"jetpack_featured_media_url":"","jetpack-related-posts":[],"jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"_links":{"self":[{"href":"https:\/\/devkico.itexto.com.br\/index.php?rest_route=\/wp\/v2\/posts\/885"}],"collection":[{"href":"https:\/\/devkico.itexto.com.br\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devkico.itexto.com.br\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devkico.itexto.com.br\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/devkico.itexto.com.br\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=885"}],"version-history":[{"count":19,"href":"https:\/\/devkico.itexto.com.br\/index.php?rest_route=\/wp\/v2\/posts\/885\/revisions"}],"predecessor-version":[{"id":906,"href":"https:\/\/devkico.itexto.com.br\/index.php?rest_route=\/wp\/v2\/posts\/885\/revisions\/906"}],"wp:attachment":[{"href":"https:\/\/devkico.itexto.com.br\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=885"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devkico.itexto.com.br\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=885"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devkico.itexto.com.br\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=885"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}