{"id":62294,"date":"2024-06-26T18:27:20","date_gmt":"2024-06-26T12:57:20","guid":{"rendered":"https:\/\/www.tothenew.com\/blog\/?p=62294"},"modified":"2024-07-01T11:28:04","modified_gmt":"2024-07-01T05:58:04","slug":"jpa-criteria-api-a-code-alternate-to-raw-sql-queries","status":"publish","type":"post","link":"https:\/\/www.tothenew.com\/blog\/jpa-criteria-api-a-code-alternate-to-raw-sql-queries\/","title":{"rendered":"JPA Criteria Api &#8211; A code alternate to raw SQL queries"},"content":{"rendered":"<h2>Introduction<\/h2>\n<p>JPA is a hibernate specification that helps us in managing, accessing &amp; persisting data between RDBMS and Java objects &amp; one of its main features is Criteria API, which is a pre-defined API and was introduced in JPA 2.0. It defines platform-independent criteria queries written in Java and enables us to achieve the same result as a raw query programmatically. It provides us with some object-oriented control over the raw SQL queries. By writing a criteria you define the where clause of a query for your specified domain class.<\/p>\n<h2>Basic components<\/h2>\n<ul>\n<li><strong>CriteriaBuilder<\/strong> \u2014 It is a factory class obtained from the entity manager to create various query-related objects such as criteriaQuery, predicates, etc.<\/li>\n<li><strong>CriteriaQuery<\/strong> \u2014 It represents the structure of the query specifying the \u201cselect\u201d clause, \u201cwhere\u201d clause &amp; ordering of the resultSet.<\/li>\n<li><strong>Root<\/strong> \u2014 This represents the Entity on which the query will operate i.e. \u201cfrom\u201d clause of a query.<\/li>\n<li><strong>Predicates<\/strong> \u2014 This represents the \u201cwhere\u201d\u00a0clause of the query.<\/li>\n<\/ul>\n<h2>Steps to Create Criteria Query<\/h2>\n<ul>\n<li>Create an EntityManagerFactory &amp; EntityManager instance.<\/li>\n<li>Create a CriteriaBuilder instance using the session\u2019s getCriteriaBuilder() method.<\/li>\n<li>Create a CriteriaQuery instance using criteriaBuilder\u2019s createQuery() method.<\/li>\n<li>Once we have created the criteriaQuery instance we need to set the query\u2019s root using its from() method.<\/li>\n<li>To get the final result, create a query instance using the session\u2019s createQuery() method by passing criteria query as an argument and then use query.getResultList() or query.getResultSet() method.<\/li>\n<\/ul>\n<h2>Implementing JPA Criteria Query<\/h2>\n<h3>Define an Entity<\/h3>\n<pre>import lombok.*;\r\nimport javax.persistence.*;\r\n\r\n@Entity\r\n@Getter\r\n@Setter\r\n@NoArgsConstructor\r\n@AllArgsConstructor\r\n@EqualsAndHashCode\r\npublic class DemoEmp {\r\n@Id\r\n@GeneratedValue(strategy= GenerationType.AUTO)\r\nprivate int id;\r\nprivate String name;\r\nprivate int salary;\r\nprivate int experience;\r\nprivate String departmentName;\r\n}<\/pre>\n<h3>Define the Criteria Builder<\/h3>\n<pre>EntityManagerFactory emf = Persistence.createEntityManagerFactory(\"my-persistence-unit\");\r\nEntityManager em = emf.createEntityManager();\r\nCriteriaBuilder criteria = em.getCriteriaBuilder(); \r\nCriteriaQuery&lt;DemoEmp&gt; cq = criteria.createQuery(DemoEmp .class); \r\nRoot&lt;DemoEmp&gt; root = cq.from(DemoEmp .class); \r\ncq.select(root); \r\nQuery&lt;DemoEmp&gt; query = em.createQuery(cq);<\/pre>\n<p>The above code will get all the rows of the DemoEmp entity from the database.<\/p>\n<h3>We can also use CriteriaBuilder for restricting query results based on the conditions using expressions<\/h3>\n<ul>\n<li>Fetch entities with salary greater than 50000<\/li>\n<\/ul>\n<pre>cq.select(root).where(criteria.gt(root.get(\"salary\"), 50000));<\/pre>\n<ul>\n<li>Fetch entities having experience between 2 and 5<\/li>\n<\/ul>\n<pre>cq.select(root).where(criteria.between(root.get(\"experience\"), 2, 5));<\/pre>\n<p>There are various other methods as well like isNull(), isNotNull(), isEmpty(), isNotEmpty(), in(), like(), aggregate methods etc.<\/p>\n<h3>We can also chain these expressions to achieve our desired condition using Predicates.<\/h3>\n<pre>Predicate greaterThanSalary = criteria.gt(root.get(\"salary\"), 50000);\r\nPredicate experience = criteria.between(root.get(\"experience\"), 2, 5);<\/pre>\n<p>Now we can join these 2 conditions with either a Logical &#8220;<strong>AND&#8221;<\/strong> or a Logical &#8220;<strong>OR&#8221;<\/strong> based on our requirement.<\/p>\n<pre>cq.select(root).where(criteria.or(greaterThanSalary, experience));\r\ncq.select(root).where(criteria.and(greaterThanSalary, experience));<\/pre>\n<h2>GroupBy &amp; Having Clause<\/h2>\n<p>The AbstractQuery interface of Criteria API has two methods <strong>groupBy()<\/strong> and <strong>having()<\/strong> which are used to filter the data by grouping them and to set the desired conditions on the grouped data respectively.<\/p>\n<pre>CriteriaQuery&lt;DemoEmp&gt; cq = criteria.createQuery(DemoEmp .class); \r\nRoot&lt;DemoEmp&gt; root = cq.from(DemoEmp .class); \r\ncq.multiselect(root.get(\"experience\"),criteria.count(root)).groupBy(root.get(\"experience\")); \r\nList&lt;Object[]&gt; results = em.createQuery(cq).getResultList();<\/pre>\n<p>In the above code, we are grouping the number of DempEmp based on their experience.<\/p>\n<pre>CriteriaQuery&lt;DemoEmp&gt; cq = criteria.createQuery(DemoEmp .class); \r\nRoot&lt;DemoEmp&gt; root = cq.from(DemoEmp .class); \r\ncq.multiselect(root.get(\"experience\"),criteria.count(root)).groupBy(root.get(\"experience\")).having(criteria.ge(root.get(\"experience\"),\u00a05));\u00a0\u00a0\r\nList&lt;Object[]&gt; results = em.createQuery(cq).getResultList();<\/pre>\n<p>In the above code, we are grouping the number of DempEmp having an <strong>experience<\/strong> either equal or greater than <strong>5<\/strong>.<\/p>\n<h2>CriteriaUpdates<\/h2>\n<p>CriteriaUpdates feature allows us to update multiple records in the database using Criteria API. We can create a CriteriaUpdate instance using CriteriaBuilder&#8217;s createCriteriaUpdate() method.<\/p>\n<p>This interface has a <strong>set()<\/strong> method that enables us to update the existing record with the desired value. We can update multiple attributes &amp; multiple records simultaneously.<\/p>\n<pre>CriteriaUpdate&lt;DemoEmp&gt; criteriaUpdate = criteria.createCriteriaUpdate(DemoEmp.class); \r\nRoot&lt;DemoEmp&gt; root = criteriaUpdate.from(DemoEmp.class); \r\ncriteriaUpdate.set(\"experience\", 10); \r\ncriteriaUpdate.set(\"salary\", 1000000); \r\ncriteriaUpdate.where(criteria.equal(root.get(\"id\"), 5))\r\nem.createQuery(criteriaUpdate).executeUpdate();<\/pre>\n<p>The above code will update the <strong>experience<\/strong> attribute value to <strong>10<\/strong> &amp; <strong>salary<\/strong> attribute value to <strong>100000<\/strong> for the DemoEmp with <strong>id =5<\/strong><\/p>\n<h2>CriteriaDelete<\/h2>\n<p>CriteriaDelete feature allows us to delete multiple records from the database using Criteria API. We can create a CriteriaDelete instance using CriteriaBuilder&#8217;s createCriteriaDelete() method. We can delete multiple records by providing a where clause for restrictions.<\/p>\n<pre>CriteriaDelete&lt;DemoEmp&gt; criteriaDelete = criteria.createCriteriaDelete(DemoEmp.class);\r\nRoot&lt;DemoEmp&gt; root = criteriaDelete.from(DemoEmp.class); \r\ncriteriaDelete.where(criteria.equal(root.get(\"departmentName\"), \"Research\")); \r\nem.createQuery(criteriaDelete).executeUpdate();<\/pre>\n<p>The above code will delete all the employees of the &#8220;<strong>Research<\/strong>&#8221; department.<\/p>\n<h2>Criteria Join<\/h2>\n<p>JPA provides a Join interface for performing joins for retrieving data from various interconnected database tables. We can perform multiple joins within a single query as well. To understand this in detail let&#8217;s change our entity and add some relationships to practice joins.<\/p>\n<h3>Updated Entity<\/h3>\n<pre>import lombok.*;\r\nimport javax.persistence.*; \r\nimport java.util.List;\r\n\r\n@Entity \r\n@Getter \r\n@Setter \r\n@NoArgsConstructor \r\n@AllArgsConstructor \r\n@Builder \r\n@EqualsAndHashCode \r\npublic class DemoEmp { \r\n@Id \r\n@GeneratedValue(strategy= GenerationType.AUTO) \r\nprivate int id; \r\nprivate String name; \r\nprivate int salary; \r\nprivate int experience; \r\nprivate String departmentName;\r\n\r\n@ManyToMany(fetch = FetchType.LAZY)\r\n@JoinTable(name = \"demo_emp_project_mapping\",\r\njoinColumns = {@JoinColumn(name = \"demo_emp_id\")},\r\ninverseJoinColumns = {@JoinColumn(name = \"project_id\")}\r\n)\r\n@JsonBackReference\r\nprivate List&lt;Project&gt; projects;\r\n\r\n@ElementCollection\r\nprivate List&lt;String&gt; certifications;\r\n}<\/pre>\n<pre>import lombok.*;\r\nimport javax.persistence.*;\r\n\r\n@Entity \r\n@Getter \r\n@Setter \r\n@NoArgsConstructor \r\n@AllArgsConstructor \r\n@EqualsAndHashCode \r\npublic class Project {\r\n@Id \r\n@GeneratedValue(strategy= GenerationType.AUTO) \r\nprivate int id; \r\nprivate String name;\r\n\r\n@ManyToMany(mappedBy = \"projects\")\r\n@JsonBackReference\r\nprivate List&lt;DemoEmp&gt; employees;\r\n}<\/pre>\n<pre>CriteriaQuery&lt;DemoEmp&gt; cq = criteria.createQuery(DemoEmp .class); \r\nRoot&lt;DemoEmp&gt; root = cq.from(DemoEmp .class); \r\nList&lt;Predicate&gt; conditions = new ArrayList();\r\n\r\nListJoin&lt;DemoEmp, String&gt; empCertificationJoin = root.joinList(\"certifications\");\r\nconditions.add(criteria.equal(empCertificationJoin, \"XYZ_Certification\"));\r\n\r\nJoin&lt;DemoEmp, Project&gt; empProjectJoin = root.join(\"projects\");\r\nconditions.add(criteria.equal(empProjectJoin.get(\"id\"), 1));\r\n\r\ncq.orderBy( criteria.asc(root.get(\"salary\")), criteria.desc(root.get(\"experience\")));\r\ncq.select(root).where(conditions.toArray(new Predicate[]{})).distinct(true);\r\n\r\nList&lt;DempEmp&gt; finalOutput = em.createQuery(cq).getResultList;<\/pre>\n<p>The above code will retrieve all the employees having &#8220;<strong>XYZ_Certification<\/strong>&#8221; and worked on the project with id &#8220;<strong>1<\/strong>&#8220;. CriteriaQuery&#8217;s &#8220;<strong>where(conditions.toArray(new Predicate[]{}))<\/strong>&#8221; combines all the predicates present in the list in a logical &#8220;<strong>and<\/strong>&#8220;.<\/p>\n<h2>Benefits of using Criteria Queries<\/h2>\n<ul>\n<li><strong>Dynamic Query Building<\/strong> \u2014 Nice, clean &amp; object-oriented API dynamic code<\/li>\n<li><strong>Type-Safety<\/strong> \u2014 It has the type-safety benefits of Java.<\/li>\n<li><strong>Metamodel Integration<\/strong> \u2014 Compile time error detection.<\/li>\n<li><strong>Refactoring Support<\/strong> \u2014 Easy to modify as it provides better support for dynamic queries as compared to HQL &amp; JPQL.<\/li>\n<\/ul>\n<h2>Conclusion<\/h2>\n<p>JPA Criteria Query API is a powerful feature that allows you to write a clean, object-oriented, type-safe code. The CriteriaUpdate &amp; CriteriaDelete introduced in JPA 2.1 make JPA Criteria API a better solution by providing the condition-specific bulk update &amp; delete functionality that was missing in the earlier version. Criteria Joins provides us precision, flexibility, and efficiency as we can define complex conditions for merging data using multiple criteria and logical operators. Using criteria for joins helps us ignore the unnecessary matches and reduces the dataset size which helps to improve performance while dealing with large datasets.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction JPA is a hibernate specification that helps us in managing, accessing &amp; persisting data between RDBMS and Java objects &amp; one of its main features is Criteria API, which is a pre-defined API and was introduced in JPA 2.0. It defines platform-independent criteria queries written in Java and enables us to achieve the same [&hellip;]<\/p>\n","protected":false},"author":1819,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":134},"categories":[446],"tags":[5991,4844,5902],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/62294"}],"collection":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/users\/1819"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/comments?post=62294"}],"version-history":[{"count":2,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/62294\/revisions"}],"predecessor-version":[{"id":62298,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/62294\/revisions\/62298"}],"wp:attachment":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/media?parent=62294"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/categories?post=62294"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/tags?post=62294"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}