View Javadoc
1   package ejava.jpa.examples.query.criteria;
2   
3   import static org.junit.Assert.assertEquals;
4   import static org.junit.Assert.assertNotNull;
5   import static org.junit.Assert.assertTrue;
6   import static org.junit.Assert.fail;
7   
8   import java.math.BigDecimal;
9   import java.text.NumberFormat;
10  import java.util.Arrays;
11  import java.util.Date;
12  import java.util.List;
13  import java.util.Map;
14  
15  import javax.persistence.EntityManager;
16  import javax.persistence.Tuple;
17  import javax.persistence.TypedQuery;
18  import javax.persistence.criteria.CriteriaBuilder;
19  import javax.persistence.criteria.CriteriaBuilder.Trimspec;
20  import javax.persistence.criteria.CriteriaQuery;
21  import javax.persistence.criteria.CriteriaUpdate;
22  import javax.persistence.criteria.Join;
23  import javax.persistence.criteria.JoinType;
24  import javax.persistence.criteria.Predicate;
25  import javax.persistence.criteria.Root;
26  import javax.persistence.criteria.Subquery;
27  
28  import org.apache.commons.logging.Log;
29  import org.apache.commons.logging.LogFactory;
30  import org.hibernate.LazyInitializationException;
31  import org.junit.Test;
32  
33  import ejava.jpa.examples.query.Clerk;
34  import ejava.jpa.examples.query.Customer;
35  import ejava.jpa.examples.query.QueryBase;
36  import ejava.jpa.examples.query.Receipt;
37  import ejava.jpa.examples.query.Sale;
38  import ejava.jpa.examples.query.Store;
39  
40  public class CriteriaTest extends QueryBase {
41  	private static final Log log = LogFactory.getLog(CriteriaTest.class);
42  
43  	private <T> List<T> executeQuery(CriteriaQuery<T> qdef) {
44          return executeQuery(qdef, null);
45      }
46  
47      private <T> List<T> executeQuery(CriteriaQuery<T> qdef, 
48              Map<String, Object> params) {
49          TypedQuery<T> query = em.createQuery(qdef);
50          if (params != null && !params.isEmpty()) {
51              for(String key: params.keySet()) {
52                  query.setParameter(key, params.get(key));
53              }
54          }
55          List<T> objects = query.getResultList();
56          for(T o: objects) {
57             log.info("found result:" + o);
58          }
59          return objects;
60      }
61  	
62      /**
63       * This test demonstrates a single entity query.
64       */
65  	@Test
66      public void testSimpleSelect() {
67          log.info("*** testSimpleSelect() ***");
68          
69          CriteriaBuilder cb = em.getCriteriaBuilder();
70          CriteriaQuery<Customer> qdef = cb.createQuery(Customer.class);
71          
72          //"select object(c) from Customer as c"
73          Root<Customer> c = qdef.from(Customer.class);        
74          qdef.select(c);
75          
76          TypedQuery<Customer> query = em.createQuery(qdef);
77          List<Customer> results = query.getResultList();
78          for (Customer result : results) {
79          	log.info("found=" + result);
80          }
81          int rows = results.size();
82          assertTrue("unexpected number of customers:" + rows, rows > 0);
83      }
84  	
85      /**
86       * This test demonstrates querying for a non-entity. The property queried
87       * for is located off a path from the root query term.
88       */
89      @Test
90      public void testNonEntityQuery() {
91          log.info("*** testNonEntityQuery() ***");
92  
93          CriteriaBuilder cb = em.getCriteriaBuilder();
94          CriteriaQuery<String> qdef = cb.createQuery(String.class);
95          
96          //select c.lastName from Customer c
97          Root<Customer> c = qdef.from(Customer.class);
98          qdef.select(c.<String>get("lastName"));
99          
100         TypedQuery<String> query = em.createQuery(qdef);
101         List<String> results = query.getResultList();
102         assertTrue("no results", results.size() > 0);
103         for(String result : results) {
104             log.info("lastName=" + result);
105         }
106     }
107 	
108     /**
109      * This test demonstrates a query for multiple properties. In this
110      * version we will use a generic Object[] for the return type.
111      */
112     @Test
113     public void testMultiSelectObjectArray() {
114         log.info("*** testMultiSelectObjectArray() ***");
115 
116         CriteriaBuilder cb = em.getCriteriaBuilder();
117         CriteriaQuery<Object[]> qdef = cb.createQuery(Object[].class);
118         
119         //select c.firstName, c.hireDate from Clerk c
120         Root<Clerk> c = qdef.from(Clerk.class);
121         qdef.select(cb.array(c.get("firstName"), c.get("hireDate")));
122         
123         TypedQuery<Object[]> query = em.createQuery(qdef);
124         List<Object[]> results = query.getResultList();
125         assertTrue("no results", results.size() > 0);
126         for(Object[] result : results) {
127             assertEquals("unexpected result length", 2, result.length);
128             String firstName = (String) result[0];
129             Date hireDate = (Date) result[1];
130             log.info("firstName=" + firstName + " hireDate=" + hireDate);
131         }
132     }
133 
134     /**
135      * This query demonstrates a query for multiple properties -- same as above
136      * -- except this example used a Tuple return type and select aliases 
137      */
138     @Test
139     public void testMultiSelectTuple() {
140         log.info("*** testMultiSelectTuple() ***");
141 
142         CriteriaBuilder cb = em.getCriteriaBuilder();
143         CriteriaQuery<Tuple> qdef = cb.createTupleQuery();
144         
145         //select c.firstName as firstName, c.hireDate as hireDate from Clerk c
146         Root<Clerk> c = qdef.from(Clerk.class);
147         qdef.select(cb.tuple(
148         		c.get("firstName").alias("firstName"), 
149         		c.get("hireDate").alias("hireDate")));
150 
151         TypedQuery<Tuple> query = em.createQuery(qdef);
152         List<Tuple> results = query.getResultList();
153         assertTrue("no results", results.size() > 0);
154         for(Tuple result : results) {
155             assertEquals("unexpected result length", 2, result.getElements().size());
156             String firstName = result.get("firstName", String.class);
157             Date hireDate = result.get("hireDate", Date.class);
158             log.info("firstName=" + firstName + " hireDate=" + hireDate);
159         }
160     }
161     
162     /**
163      * This test provides another demonstration of selecting multiple properties --
164      * with this example using a constructor expression to return a typed 
165      * object for each result in the query.
166      */
167     @Test
168     public void testMultiSelectConstructor() {
169         log.info("*** testMultiSelectConstructor() ***");
170 
171         CriteriaBuilder cb = em.getCriteriaBuilder();
172         CriteriaQuery<Receipt> qdef = cb.createQuery(Receipt.class);
173         
174         //select new ejava.jpa.examples.query.Receipt(s.id,s.buyerId,s.date, s.amount)
175         //from Sale s
176         Root<Sale> s = qdef.from(Sale.class);
177         qdef.select(cb.construct(
178 		        		Receipt.class, 
179 		        		s.get("id"), 
180 		        		s.get("buyerId"),
181 		        		s.get("date"),
182 		        		s.get("amount")));
183         
184         TypedQuery<Receipt> query = em.createQuery(qdef);
185         List<Receipt> results = query.getResultList();
186         assertTrue("no results", results.size() > 0);
187         for(Receipt receipt : results) {
188             assertNotNull("no receipt", receipt);
189             log.info("receipt=" + receipt);
190         }        
191     }
192 
193     /**
194      * This test provides an example of navigating a path formed by a 
195      * relationship. In this case the path used is a single element.
196      */
197     @Test
198     public void testPathExpressions() {
199         log.info("*** testPathExpressions() ***");
200 
201         CriteriaBuilder cb = em.getCriteriaBuilder();
202         CriteriaQuery<Object[]> qdef = cb.createQuery(Object[].class);
203         
204         //select s.id, s.store.name from Sale s
205         Root<Sale> s = qdef.from(Sale.class);
206         qdef.select(cb.array(s.get("id"),
207         		             s.get("store").get("name")));
208         
209         TypedQuery<Object[]> query = em.createQuery(qdef);
210         List<Object[]> results = query.getResultList();
211         assertTrue("no results", results.size() > 0);
212         for(Object[] result : results) {
213             assertEquals("unexpected result length", 2, result.length);
214             Long id = (Long) result[0];
215             String name = (String) result[1];
216             log.info("sale.id=" + id + ", sale.store.name=" + name);
217         }
218     }
219 
220     /**
221      * This test provides an example collection path using an INNER JOIN
222      */
223     @Test
224     public void testCollectionPathExpressionsInnerJoin() {
225         log.info("*** testCollectionPathExpressionsInnerJoin ***");
226 
227         CriteriaBuilder cb = em.getCriteriaBuilder();
228         CriteriaQuery<Date> qdef = cb.createQuery(Date.class);
229         
230         //select sale.date from Clerk c JOIN c.sales sale
231         Root<Clerk> c = qdef.from(Clerk.class);
232         Join<Clerk, Sale> sale = c.join("sales", JoinType.INNER);
233         qdef.select(sale.<Date>get("date"));
234 
235         int rows=executeQuery(qdef).size();
236         assertTrue("unexpected number of sales:" + rows, rows > 0);
237     }
238 
239     /**
240      * This test provides an example collection path using an LEFT OUTER JOIN
241      */
242     @Test
243     public void testOuterJoin() {
244         log.info("*** testOuterJoin() ***");
245         
246         CriteriaBuilder cb = em.getCriteriaBuilder();
247         CriteriaQuery<Object[]> qdef = cb.createQuery(Object[].class);
248         
249         //select c.id, c.firstName, sale.amount 
250         //from Clerk c 
251         //LEFT JOIN c.sales sale
252         Root<Clerk> c = qdef.from(Clerk.class);
253         Join<Clerk, Sale> sale = c.join("sales", JoinType.LEFT);
254         qdef.select(cb.array(c.get("id"),
255         		             c.get("firstName"),
256         		             sale.get("amount")));
257         
258         TypedQuery<Object[]> query = em.createQuery(qdef);
259         List<Object[]> results = query.getResultList();
260         assertTrue("no results", results.size() > 0);
261         for(Object[] result : results) {
262             assertEquals("unexpected result length", 3, result.length);
263             Long id = (Long) result[0];
264             String name = (String) result[1];
265             BigDecimal amount = (BigDecimal) result[2];
266             log.info("clerk.id=" + id + ", clerk.firstName=" + name +
267                     ", amount=" + amount);
268         }
269     }
270     
271     /**
272      * This test demonstrates creating an explicit JOIN based on adhoc criteria
273      */
274     @Test
275     public void testExplicitJoin() {
276     	log.info("*** testExplicitJoin ***");
277     	
278     	CriteriaBuilder cb = em.getCriteriaBuilder();
279     	CriteriaQuery<Customer> qdef = cb.createQuery(Customer.class);
280     	
281     	//select c from Sale s, Customer c 
282     	//where c.id = s.buyerId
283     	Root<Sale> s = qdef.from(Sale.class);
284     	Root<Customer> c = qdef.from(Customer.class);
285     	qdef.select(c)
286     	    .where(cb.equal(c.get("id"), s.get("buyerId")));
287     	
288     	int rows = executeQuery(qdef).size();
289         assertTrue("unexpected number of customers:" + rows, rows > 0);
290     }
291     
292     /**
293      * This test demonstrates the function of a JOIN FETCH to perform the 
294      * EAGER retrieval of entities as a side-effect of the query
295      */
296     @Test
297     public void testFetchJoin1() {        
298         log.info("** testFetchJoin1() ***");
299         
300         EntityManager em2 = createEm();
301         CriteriaBuilder cb = em2.getCriteriaBuilder();
302         CriteriaQuery<Store> qdef = cb.createQuery(Store.class);
303         
304         //select s from Store s JOIN s.sales
305         //where s.name='Big Al''s'
306         Root<Store> s = qdef.from(Store.class);
307         s.join("sales");
308         qdef.select(s)
309             .where(cb.equal(s.get("name"), "Big Al's"));
310         
311         Store store = em2.createQuery(qdef).getSingleResult();
312         log.info("em.contains(" + em2.contains(store) + ")");
313         em2.close();
314         try {
315         	store.getSales().get(0).getAmount();
316         	fail("did not trigger lazy initialization exception");
317         } catch (LazyInitializationException expected) {
318         	log.info("caught expected exception:" + expected);
319         }
320     }
321     @Test
322     public void testFetchJoin2() {        
323         log.info("** testFetchJoin2() ***");
324 
325         EntityManager em2 = createEm();
326         CriteriaBuilder cb = em2.getCriteriaBuilder();
327         CriteriaQuery<Store> qdef = cb.createQuery(Store.class);
328 
329         //select s from Store s JOIN FETCH s.sales
330         //where s.name='Big Al''s'
331         Root<Store> s = qdef.from(Store.class);
332         s.fetch("sales");
333         qdef.select(s)
334             .where(cb.equal(s.get("name"), "Big Al's"));
335         
336         Store store = em2.createQuery(qdef).getSingleResult();
337         log.info("em.contains(" + em2.contains(store) + ")");
338         em2.close();
339        	store.getSales().get(0).getAmount();
340     }
341     
342     /**
343      * This test demonstrates the use of DISTINCT to limit the results
344      * to only unique values
345      */
346     @Test
347     public void testDISTINCT() {
348         log.info("*** testDISTINCT() ***");
349 
350         CriteriaBuilder cb = em.getCriteriaBuilder();
351         {
352 	        CriteriaQuery<String> qdef = cb.createQuery(String.class);
353 	        
354 	        //select DISTINCT c.lastName from Customer c
355 	        Root<Customer> c = qdef.from(Customer.class);
356 	        qdef.select(c.<String>get("lastName"))
357 	            .distinct(true);
358 	        
359 	        int rows = executeQuery(qdef).size();
360 	        assertEquals("unexpected number of rows", 3, rows);
361         }
362         
363         {        
364         	CriteriaQuery<String> qdef = cb.createQuery(String.class);
365         	
366         	//select DISTINCT c.firstName from Customer c
367         	Root<Customer> c = qdef.from(Customer.class);
368         	qdef.select(c.<String>get("firstName"))
369         		.distinct(true);
370         
371 	        int rows = executeQuery(qdef).size();
372 	        assertEquals("unexpected number of rows for DISTINCT", 2, rows);
373         }
374     }
375     
376     //where clauses
377     
378     
379     /**
380      * This test provides an example of an equality test in the where clause
381      */
382     @Test
383     public void testLiteral() {
384         log.info("*** testLiteral() ***");
385         
386         CriteriaBuilder cb = em.getCriteriaBuilder();
387         CriteriaQuery<Customer> qdef = cb.createQuery(Customer.class);
388         
389         //select c from Customer c 
390         //where c.firstName='cat'
391         Root<Customer> c = qdef.from(Customer.class);
392         qdef.select(c)
393             .where(cb.equal(c.get("firstName"), "cat"));
394         
395         int rows = executeQuery(qdef).size();
396         assertEquals("unexpected number of rows:", 1, rows);
397     }
398 
399     /**
400      * This test demonstrates how literal values are automatically escaped
401      */
402     @Test
403     public void testSpecialCharacter() {
404         log.info("*** testSpecialCharacter() ***");
405 
406         CriteriaBuilder cb = em.getCriteriaBuilder();
407         CriteriaQuery<Store> qdef = cb.createQuery(Store.class);
408         
409         //select s from Store s 
410         //where s.name='Big Al''s'
411         Root<Store> s = qdef.from(Store.class);
412         qdef.select(s)
413             .where(cb.equal(s.get("name"), "Big Al's"));
414         
415         int rows = executeQuery(qdef).size();
416         assertEquals("unexpected number of rows", 1, rows);
417     }
418     
419     /**
420      * This test demonstrates the use of like in where clauses
421      */
422     @Test
423     public void testLike() {
424         log.info("*** testLike() ***");
425         
426         CriteriaBuilder cb = em.getCriteriaBuilder();
427         {
428         	CriteriaQuery<Clerk> qdef = cb.createQuery(Clerk.class);
429         	
430         	//select c from Clerk c 
431             //where c.firstName like 'M%'
432         	Root<Clerk> c = qdef.from(Clerk.class);
433         	qdef.select(c)
434         	    .where(cb.like(c.<String>get("firstName"), "M%"));
435 
436         	int rows = executeQuery(qdef).size();
437         	assertEquals("unexpected number of rows", 2, rows);
438         }
439         
440         {
441         	CriteriaQuery<Clerk> qdef = cb.createQuery(Clerk.class);
442         	
443         	//select c from Clerk c
444             //where c.firstName like :firstName
445         	Root<Clerk> c = qdef.from(Clerk.class);
446         	qdef.select(c)
447         	    .where(cb.like(c.<String>get("firstName"), 
448         	    		       cb.parameter(String.class, "firstName")));
449         	TypedQuery<Clerk> query = em.createQuery(qdef)
450         			.setParameter("firstName", "M%");
451         	List<Clerk> results = query.getResultList();
452             for(Object o: results) {
453                 log.info("found result:" + o);
454              }
455             assertEquals("unexpected number of rows", 2, results.size());        
456         }
457         
458         {
459         	CriteriaQuery<Clerk> qdef = cb.createQuery(Clerk.class);
460         	
461         	//select c from Clerk c
462             //where c.firstName like concat(:firstName,'%')
463         	Root<Clerk> c = qdef.from(Clerk.class);
464         	qdef.select(c)
465         	    .where(cb.like(c.<String>get("firstName"),
466         	    		       cb.concat(cb.parameter(String.class, "firstName"), "%")));
467         	TypedQuery<Clerk> query = em.createQuery(qdef)
468         			.setParameter("firstName", "M");
469         	List<Clerk> results = query.getResultList();
470             for(Object o: results) {
471                 log.info("found result:" + o);
472              }
473             assertEquals("unexpected number of rows", 2, results.size());        
474         }
475         
476         {
477         	CriteriaQuery<Clerk> qdef = cb.createQuery(Clerk.class);
478         	
479         	//select c from Clerk c
480             //where c.firstName like '_anny'
481         	Root<Clerk> c = qdef.from(Clerk.class);
482         	qdef.select(c)
483         	    .where(cb.like(c.<String>get("firstName"),"_anny"));
484         	TypedQuery<Clerk> query = em.createQuery(qdef);
485         	List<Clerk> results = query.getResultList();
486             for(Object o: results) {
487                 log.info("found result:" + o);
488              }
489             assertEquals("unexpected number of rows", 1, results.size());        
490         }
491         
492     }
493     
494     /**
495      * This test provides a demonstration of using a math formual within the 
496      * where clause.
497      */
498     @Test
499     public void testFormulas() {
500         log.info("*** testFormulas() ***");
501 
502         CriteriaBuilder cb = em.getCriteriaBuilder();
503         CriteriaQuery<Number> qdef = cb.createQuery(Number.class); 
504         
505         //select count(s) from Sale s 
506         //where (s.amount * :tax) > :amount"
507         Root<Sale> s = qdef.from(Sale.class);
508         qdef.select(cb.count(s))
509             .where(cb.greaterThan(
510             	cb.prod(s.<BigDecimal>get("amount"), cb.parameter(BigDecimal.class, "tax")), 
511             	new BigDecimal(10.0)));
512         TypedQuery<Number> query = em.createQuery(qdef);
513                 
514         //keep raising taxes until somebody pays $10.00 in tax
515         double tax = 0.05;
516         for (;query.setParameter("tax", new BigDecimal(tax))
517         		   .getSingleResult().intValue()==0;
518         	  tax += 0.01) {
519         	log.debug("tax=" + NumberFormat.getPercentInstance().format(tax));
520         }
521         log.info("raise taxes to: " + NumberFormat.getPercentInstance().format(tax));
522         
523         assertEquals("unexpected level for tax:" + tax, 0.07, tax, .01);
524     }
525     
526     /**
527      * This test provides a demonstration of using logical AND, OR, and NOT
528      * within a query where clause
529      */
530     @Test
531     public void testLogical() {
532         log.info("*** testLogical() ***");
533 
534         CriteriaBuilder cb = em.getCriteriaBuilder();
535         
536         {
537         	CriteriaQuery<Customer> qdef = cb.createQuery(Customer.class);
538         	
539         	//select c from Customer c 
540             //where (c.firstName='cat' AND c.lastName='inhat')
541             //  OR c.firstName='thing'
542         	Root<Customer> c = qdef.from(Customer.class);
543         	qdef.select(c)
544         	    .where(cb.or(
545         	    		cb.and(cb.equal(c.get("firstName"), "cat"), 
546         	    			   cb.equal(c.get("lastName"), "inhat")),
547         	    		cb.equal(c.get("firstName"), "thing")));
548         	
549         	int rows=executeQuery(qdef).size();
550             assertEquals("unexpected number of rows", 3, rows);        
551         }
552 
553         {
554         	CriteriaQuery<Customer> qdef = cb.createQuery(Customer.class);
555         	
556             //select c from Customer c
557             //where (NOT (c.firstName='cat' AND c.lastName='inhat'))
558             //  OR c.firstName='thing'
559         	Root<Customer> c = qdef.from(Customer.class);
560         	qdef.select(c)
561         	    .where(cb.or(
562 	        	    	cb.not(cb.and(cb.equal(c.get("firstName"), "cat"), 
563 	        	    		          cb.equal(c.get("lastName"), "inhat"))),
564         	    		cb.equal(c.get("firstName"), "thing"))
565         	    	);
566         	
567         	int rows=executeQuery(qdef).size();
568             assertEquals("unexpected number of rows", 2, rows);        
569         }
570     }
571 
572     /**
573      * This test provides a demonstration for comparing two entities within
574      * a query
575      */
576     @Test
577     public void testEquality() {
578         log.info("*** testEquality() ***");
579         
580         CriteriaBuilder cb = em.getCriteriaBuilder();
581        	CriteriaQuery<Clerk> qdef = cb.createQuery(Clerk.class);
582 
583        	//select c from Clerk c where c.firstName = 'Manny'", 
584        	Root<Clerk> c = qdef.from(Clerk.class);
585        	qdef.select(c)
586        	    .where(cb.equal(c.get("firstName"), "Manny"));
587        	Clerk clerk = em.createQuery(qdef).getSingleResult();
588 
589        	//find all sales that involve this clerk
590        	
591         //select s from Sale s
592         //JOIN s.clerks c
593         //where c = :clerk 
594        	CriteriaQuery<Sale> qdef2 = cb.createQuery(Sale.class);
595        	Root<Sale> s = qdef2.from(Sale.class);
596        	Join<Sale, Clerk> c2 = s.join("clerks");
597        	qdef2.select(s)
598        	     .where(cb.equal(c2, clerk));
599        	
600         List<Sale> sales = em.createQuery(qdef2)
601 	            .getResultList();
602         for (Sale result : sales) {
603         	log.info("found=" + result);
604         }
605         assertEquals("unexpected number of rows", 2, sales.size());
606     }
607     
608     /**
609      * This test provides an example of using between condition
610      */
611     @Test
612     public void testBetween() {
613         log.info("*** testBetween() ***");
614 
615         CriteriaBuilder cb = em.getCriteriaBuilder();
616         {
617 	        CriteriaQuery<Sale> qdef = cb.createQuery(Sale.class);
618 	        
619 	        //select s from Sale s
620 	        //where s.amount BETWEEN :low AND :high"
621 	        Root<Sale> s = qdef.from(Sale.class);
622 	        qdef.select(s)
623 	            .where(cb.between(s.<BigDecimal>get("amount"), 
624 		            		new BigDecimal(90.00), 
625 		            		new BigDecimal(110.00)));
626 	        List<Sale> sales = em.createQuery(qdef).getResultList();
627 	        for (Sale result : sales) {
628 	        	log.info("found=" + result);
629 	        }
630 	        assertEquals("unexpected number of rows", 1, sales.size());
631         }
632 
633         {
634 	        CriteriaQuery<Sale> qdef = cb.createQuery(Sale.class);
635 	        
636 	        //select s from Sale s
637 	        //where s.amount NOT BETWEEN :low AND :high"
638 	        Root<Sale> s = qdef.from(Sale.class);
639 	        qdef.select(s)
640 	            .where(cb.not(cb.between(s.<BigDecimal>get("amount"), 
641 		            		new BigDecimal(90.00), 
642 		            		new BigDecimal(110.00))));
643 	        List<Sale> sales = em.createQuery(qdef).getResultList();
644 	        for (Sale result : sales) {
645 	        	log.info("found=" + result);
646 	        }
647 	        assertEquals("unexpected number of rows", 1, sales.size());
648         }
649     }
650     
651     /**
652      * This test provides a demonstration of testing for a null value.
653      */
654     @Test
655     public void testIsNull() {
656         log.info("*** testIsNull() ***");
657         
658         CriteriaBuilder cb = em.getCriteriaBuilder();
659         {
660             CriteriaQuery<Sale> qdef = cb.createQuery(Sale.class);
661             
662             //select s from Sale s 
663             //where s.store IS NULL
664             Root<Sale> s = qdef.from(Sale.class);
665             qdef.select(s)
666                 .where(cb.isNull(s.get("store")));
667             	//.where(cb.equal(s.get("store"), cb.nullLiteral(Store.class)));
668                     
669             List<Sale> sales = em.createQuery(qdef).getResultList();
670             for (Sale result : sales) {
671             	log.info("found=" + result);
672             }
673             assertEquals("unexpected number of rows", 0, sales.size());
674         }
675         {
676             CriteriaQuery<Sale> qdef = cb.createQuery(Sale.class);
677             
678             //select s from Sale s 
679             //where s.store IS NOT NULL
680             Root<Sale> s = qdef.from(Sale.class);
681             qdef.select(s)
682                 .where(cb.isNotNull(s.get("store")));
683             	//.where(cb.not(cb.equal(s.get("store"), cb.nullLiteral(Store.class))));
684                     
685             List<Sale> sales = em.createQuery(qdef).getResultList();
686             for (Sale result : sales) {
687             	log.info("found=" + result);
688             }
689             assertEquals("unexpected number of rows", 2, sales.size());
690         }
691     }
692     
693     /**
694      * This test provides an example of testing whether the collection
695      * is empty
696      */
697     @Test
698     public void testIsEmpty() {
699         log.info("*** testIsEmpty() ***");
700 
701         CriteriaBuilder cb = em.getCriteriaBuilder();
702         {
703             CriteriaQuery<Clerk> qdef = cb.createQuery(Clerk.class);
704             
705             //select c from Clerk c
706             //where c.sales IS EMPTY
707             Root<Clerk> c = qdef.from(Clerk.class);
708             qdef.select(c)
709                 .where(cb.isEmpty(c.<List<Sale>>get("sales")));
710             
711             int rows = executeQuery(qdef).size();
712             assertEquals("unexpected number of rows", 1, rows);
713         }
714 
715         {
716             CriteriaQuery<Clerk> qdef = cb.createQuery(Clerk.class);
717             
718             //select c from Clerk c
719             //where c.sales IS NOT EMPTY
720             Root<Clerk> c = qdef.from(Clerk.class);
721             qdef.select(c)
722                 .where(cb.isNotEmpty(c.<List<Sale>>get("sales")));
723             
724             int rows = executeQuery(qdef).size();
725             assertEquals("unexpected number of rows", 2, rows);
726         }
727     }
728     
729     /**
730      * This test provides a demonstration of testing membership in 
731      * a collection.
732      */
733     @Test
734     public void testMemberOf() {
735         log.info("*** testMemberOf() ***");
736         
737         CriteriaBuilder cb = em.getCriteriaBuilder();
738         CriteriaQuery<Clerk> qdef = cb.createQuery(Clerk.class);
739         
740         //select c from Clerk c where c.firstName = 'Manny'
741         Root<Clerk> c = qdef.from(Clerk.class);
742         qdef.select(c)
743             .where(cb.equal(c.get("firstName"), "Manny"));
744         Clerk clerk = em.createQuery(qdef).getSingleResult();
745         
746         //find all sales that involve this clerk
747         CriteriaQuery<Sale> qdef2 = cb.createQuery(Sale.class);
748         //select s from Sale s
749         //where :clerk MEMBER OF s.clerks",
750         Root<Sale> s = qdef2.from(Sale.class);
751         qdef2.select(s)
752              .where(cb.isMember(clerk, s.<List<Clerk>>get("clerks")));
753         List<Sale> sales = em.createQuery(qdef2).getResultList();
754         
755         for (Sale result : sales) {
756         	log.info("found=" + result);
757         }
758         assertEquals("unexpected number of rows", 2, sales.size());
759     }
760     
761     
762     /**
763      * This test provides a demonstration of using an explicit subquery
764      */
765     @Test
766     public void testSubqueries() {
767        log.info("*** testSubqueries() ***");   
768 
769        CriteriaBuilder cb = em.getCriteriaBuilder();
770        CriteriaQuery<Customer> qdef = cb.createQuery(Customer.class);
771        
772        //select c from Customer c
773  	   //where c.id IN
774        //    (select s.buyerId from Sale s
775        //     where s.amount > 100)
776        
777        		//form subquery
778        Subquery<Long> sqdef = qdef.subquery(Long.class);
779        Root<Sale> s = sqdef.from(Sale.class);
780        sqdef.select(s.<Long>get("buyerId"))
781             .where(cb.greaterThan(s.<BigDecimal>get("amount"), new BigDecimal(100)));
782 
783   		//form outer query
784    	   Root<Customer> c = qdef.from(Customer.class);
785 	   qdef.select(c)
786            .where(cb.in(c.get("id")).value(sqdef));
787 
788        int rows = executeQuery(qdef).size();
789        assertEquals("unexpected number of rows", 1, rows);
790     }
791     
792     /**
793      * This test provides a demonstration for using the ALL subquery
794      * result evaluation.
795      */
796     @Test
797     public void testAll() {
798         log.info("*** testAll() ***");  
799         
800         CriteriaBuilder cb = em.getCriteriaBuilder();
801         CriteriaQuery<Clerk> qdef = cb.createQuery(Clerk.class);
802         Root<Clerk> c = qdef.from(Clerk.class);
803         qdef.select(c);
804         
805         //select c from Clerk c
806         //where 125 < ALL " +
807         //(select s.amount from c.sales s)",
808         Subquery<BigDecimal> sqdef = qdef.subquery(BigDecimal.class);
809         Root<Clerk> c1 = sqdef.from(Clerk.class);
810         Join<Clerk,Sale> s = c1.join("sales");
811         sqdef.select(s.<BigDecimal>get("amount"))
812              .where(cb.equal(c, c1));
813 
814         Predicate p1 = cb.lessThan(
815         		cb.literal(new BigDecimal(125)), 
816         		cb.all(sqdef));
817 
818         qdef.where(p1);
819         List<Clerk> results1 = executeQuery(qdef);
820         assertEquals("unexpected number of rows", 2, results1.size());
821 
822         //select c from Clerk c
823         //where 125 > ALL
824         //(select s.amount from c.sales s)
825         Predicate p2 = cb.greaterThan(
826         		cb.literal(new BigDecimal(125)), 
827         		cb.all(sqdef));
828         
829         qdef.where(p2);
830         List<Clerk> results2 = executeQuery(qdef);
831         assertEquals("unexpected number of rows", 1, results2.size());
832     }
833     
834     
835     /**
836      * This test provides a demonstration for using the ANY subquery
837      * result evaluation
838      */
839     @Test
840     public void testAny() {
841         CriteriaBuilder cb = em.getCriteriaBuilder();
842         CriteriaQuery<Clerk> qdef = cb.createQuery(Clerk.class);
843         Root<Clerk> c = qdef.from(Clerk.class);
844         qdef.select(c);
845         
846         //select c from Clerk c
847         //where 125 < ANY " +
848         //(select s.amount from c.sales s)",
849         Subquery<BigDecimal> sqdef = qdef.subquery(BigDecimal.class);
850         Root<Clerk> c1 = sqdef.from(Clerk.class);
851         Join<Clerk,Sale> s = c1.join("sales");
852         sqdef.select(s.<BigDecimal>get("amount"))
853              .where(cb.equal(c, c1));
854 
855         Predicate p1 = cb.lessThan(
856         		cb.literal(new BigDecimal(125)), 
857         		cb.any(sqdef));
858 
859         qdef.where(p1);
860         List<Clerk> results1 = executeQuery(qdef);
861         assertEquals("unexpected number of rows", 2, results1.size());
862 
863         //select c from Clerk c
864         //where 125 > ANY
865         //(select s.amount from c.sales s)
866         Predicate p2 = cb.greaterThan(
867         		cb.literal(new BigDecimal(125)), 
868         		cb.any(sqdef));
869         
870         qdef.where(p2);
871         List<Clerk> results2 = executeQuery(qdef);
872         assertEquals("unexpected number of rows", 1, results2.size());
873      }
874     
875     
876     /**
877      * This test method demonstrates several date functions
878      */
879     @Test
880     @SuppressWarnings({ "rawtypes", "unchecked" })
881     public void testStringFunctions() {
882         log.info("*** testStringFunctions() ***");
883         
884         CriteriaBuilder cb = em.getCriteriaBuilder();
885 		CriteriaQuery qdef = cb.createQuery();
886 		Root<Customer> c = qdef.from(Customer.class);
887         
888         //select c from Customer c
889         //where c.firstName='CAT'
890         qdef.select(c)
891             .where(cb.equal(c.get("firstName"),"CAT"));
892         int rows = executeQuery(qdef).size();
893         assertEquals("unexpected number of rows", 0, rows);
894 
895         //select c from Customer c
896         //where c.firstName=LOWER('CAT')"
897         qdef.select(c)
898             .where(cb.equal(c.get("firstName"),cb.lower(cb.literal("CAT"))));
899         rows = executeQuery(qdef).size();
900         assertEquals("unexpected number of rows", 1, rows);
901             
902         //select UPPER(c.firstName) from Customer c
903         //where c.firstName=LOWER('CAT')
904         qdef.select(cb.upper(c.<String>get("firstName")))
905             .where(cb.equal(c.get("firstName"),cb.lower(cb.literal("CAT"))));
906         rows = executeQuery(qdef).size();
907         assertEquals("unexpected number of rows", 1, rows);
908 
909         //TODO: determine why SQL generated without quotes here with H2Dialect
910 /*
911 Caused by: org.h2.jdbc.JdbcSQLException: Column "C" not found; SQL statement:
912 select trim(LEADING c from customer0_.FIRST_NAME) as col_0_0_ from JPAQL_CUSTOMER customer0_ 
913 where customer0_.FIRST_NAME=?  
914 */
915         
916         //select TRIM(LEADING 'c' FROM c.firstName) from Customer c
917         //where c.firstName='cat')
918         qdef.select(cb.trim(Trimspec.LEADING, 'c', c.<String>get("firstName")))
919             .where(cb.equal(c.get("firstName"),"cat"));
920 //        List<String> result = executeQuery(qdef);        
921 //        assertEquals("unexpected number of rows", 1, rows);
922 //        assertEquals("unexpected value", "at", result.get(0));
923         
924         //select c from Customer c
925         //where CONCAT(CONCAT(c.firstName,' '),c.lastName) ='cat inhat')
926         qdef.select(c)
927         	.where(cb.equal(
928         			cb.concat(
929         					cb.concat(c.<String>get("firstName"), " "),
930         					c.<String>get("lastName")),
931         			"cat inhat"));
932         rows = executeQuery(qdef).size();
933         assertEquals("unexpected number of rows:" + rows, 1, rows);
934         
935         //select c from Customer c
936         //where LENGTH(c.firstName) = 3
937         qdef.select(c)
938             .where(cb.equal(cb.length(c.<String>get("firstName")),3));
939         rows = executeQuery(qdef).size();
940         assertEquals("unexpected number of rows:" + rows, 1, rows);
941         
942         //select c from Customer c " +
943         //where LOCATE('cat',c.firstName,2) > 0",
944         qdef.select(c)
945             .where(cb.greaterThan(cb.locate(c.<String>get("firstName"), "cat", 2),0));        
946         rows = executeQuery(qdef).size();
947         assertEquals("unexpected number of rows:" + rows, 0, rows);        
948 
949         //select c from Customer c
950         //where LOCATE('at',c.firstName,2) > 1
951         qdef.select(c)
952             .where(cb.greaterThan(cb.locate(c.<String>get("firstName"), "at", 2),1));        
953         rows = executeQuery(qdef).size();
954         assertEquals("unexpected number of rows:" + rows, 1, rows);        
955 
956         //select SUBSTRING(c.firstName,2,2) from Customer c " +
957         //where c.firstName = 'cat'",
958         qdef.select(cb.substring(c.<String>get("firstName"),  2, 2))
959             .where(cb.equal(c.get("firstName"), "cat"));
960         List<String> result = executeQuery(qdef);        
961         assertEquals("unexpected number of rows", 1, rows);
962         assertEquals("unexpected value", "at", result.get(0));
963         
964         //select c from Customer c
965         //where SUBSTRING(c.firstName,2,2) = 'at'
966         qdef.select(c)
967             .where(cb.equal(
968             		cb.substring(c.<String>get("firstName"), 2, 2), 
969             		"at"));
970         rows = executeQuery(qdef).size();
971         assertEquals("unexpected number of rows:" + rows, 1, rows);
972     }
973  
974     /**
975      * This test method demonstrates using date functions.
976      */
977     @Test
978     public void testDates() {        
979         log.info("*** testDates() ***");
980         
981         CriteriaBuilder cb = em.getCriteriaBuilder();
982         CriteriaQuery<Sale> qdef = cb.createQuery(Sale.class);
983         Root<Sale> s = qdef.from(Sale.class);
984         qdef.select(s);
985 
986         //select s from Sale s
987         //where s.date < CURRENT_DATE
988         qdef.where(cb.lessThan(s.<Date>get("date"), cb.currentDate()));        
989         int rows = executeQuery(qdef).size();
990         assertEquals("unexpected number of rows", 2, rows);
991         
992         //select s from Sale s
993         //where s.date = CURRENT_DATE
994         qdef.where(cb.equal(s.<Date>get("date"), cb.currentDate()));        
995         rows = executeQuery(qdef).size();
996         assertEquals("unexpected number of rows", 0, rows);
997 
998         //bulk query capability added to Criteria API in JPA 2.1
999         
1000         //update Sale s
1001     	//set s.date = CURRENT_DATE
1002         CriteriaUpdate<Sale> qupdate = cb.createCriteriaUpdate(Sale.class);
1003         Root<Sale> s2 = qupdate.from(Sale.class);
1004         qupdate.set(s2.<Date>get("date"), cb.currentDate());
1005         rows = em.createQuery(qupdate).executeUpdate();
1006         assertEquals("unexpected number of rows", 2, rows);
1007         
1008         em.getTransaction().commit();
1009         em.clear(); //remove stale objects in cache
1010         
1011         //select s from Sale s
1012         //where s.date = CURRENT_DATE
1013         qdef.where(cb.equal(s.<Date>get("date"), cb.currentDate()));        
1014         rows = executeQuery(qdef).size();
1015         assertEquals("unexpected number of rows", 2, rows);
1016     }
1017     
1018     /**
1019      * This test method provides a demonstration of order by capability.
1020      */
1021     @Test
1022     public void testOrderBy() {
1023         log.info("*** testOrderBy() ***");
1024 
1025         CriteriaBuilder cb = em.getCriteriaBuilder();
1026         CriteriaQuery<Sale> qdef = cb.createQuery(Sale.class);
1027         Root<Sale> s = qdef.from(Sale.class);
1028         qdef.select(s);
1029 
1030         //select s from Sale s ORDER BY s.amount ASC
1031         qdef.orderBy(cb.asc(s.get("amount")));
1032         List<Sale> results = executeQuery(qdef); 
1033         assertEquals("unexpected number of rows", 2, results.size());
1034         assertEquals("unexpected first element", 
1035                 100, 
1036                 results.get(0).getAmount().intValue());
1037         assertEquals("unexpected first element", 
1038                 150, 
1039                 results.get(1).getAmount().intValue());
1040 
1041         
1042         //select s from Sale s ORDER BY s.amount DESC
1043         qdef.orderBy(cb.desc(s.get("amount")));
1044         results = executeQuery(qdef); 
1045         assertEquals("unexpected number of rows", 2, results.size());
1046         assertEquals("unexpected first element", 
1047                 150, 
1048                 results.get(0).getAmount().intValue());
1049         assertEquals("unexpected first element", 
1050                 100, 
1051                 results.get(1).getAmount().intValue());
1052     }
1053     
1054     /**
1055      * This test provides a demonstration of the COUNT aggregate function
1056      */    
1057     @Test
1058     public void testCount() {        
1059         log.info("*** testCount() ***");
1060 
1061         CriteriaBuilder cb = em.getCriteriaBuilder();
1062         CriteriaQuery<Number> qdef = cb.createQuery(Number.class);
1063         Root<Sale> s = qdef.from(Sale.class);
1064         
1065         //select COUNT(s) from Sale s
1066         qdef.select(cb.count(s));
1067 
1068         List<Number> results= executeQuery(qdef);
1069         assertEquals("unexpected number of rows", 1, results.size());
1070         assertEquals("unexpected result", 2, results.get(0).intValue());
1071     }
1072     
1073     /**
1074      * This test provides a demonstration of the MIN and MAX aggregate functions
1075      */
1076     @Test
1077     public void testMaxMin() {        
1078         log.info("*** testMaxMin() ***");
1079 
1080         CriteriaBuilder cb = em.getCriteriaBuilder();
1081         CriteriaQuery<Number> qdef = cb.createQuery(Number.class);
1082         Root<Sale> s = qdef.from(Sale.class);
1083 
1084         //select max(s.amount) from Sale s
1085         qdef.select(cb.max(s.<BigDecimal>get("amount")));
1086         List<Number> results= executeQuery(qdef);
1087         assertEquals("unexpected number of rows", 1, results.size());
1088         assertEquals("unexpected result", 150, results.get(0).intValue());
1089         
1090         //select min(s.amount) from Sale s
1091         qdef.select(cb.min(s.<BigDecimal>get("amount")));
1092         results= executeQuery(qdef);
1093         assertEquals("unexpected number of rows", 1, results.size());
1094         assertEquals("unexpected result", 100, results.get(0).intValue());
1095     }
1096 
1097     /**
1098      * This test provides a demonstration of the SUM and AVE aggregate functions
1099      */
1100     @Test
1101     public void testSumAve() {        
1102         log.info("*** testSumAve() ***");
1103 
1104         CriteriaBuilder cb = em.getCriteriaBuilder();
1105         CriteriaQuery<Number> qdef = cb.createQuery(Number.class);
1106         Root<Sale> s = qdef.from(Sale.class);
1107 
1108         //select sum(s.amount) from Sale s
1109         qdef.select(cb.sum(s.<BigDecimal>get("amount")));
1110         List<Number> results=executeQuery(qdef);
1111         assertEquals("unexpected number of rows", 1, results.size());
1112         assertEquals("unexpected result", 250, results.get(0).intValue());
1113         
1114         //select avg(s.amount) from Sale s
1115         qdef.select(cb.avg(s.<BigDecimal>get("amount")));
1116         results= executeQuery(qdef);
1117         assertEquals("unexpected number of rows", 1, results.size());
1118         assertEquals("unexpected result", 125, results.get(0).intValue());
1119     }
1120     
1121     /**
1122      * This test method provides an example of using group by 
1123      */
1124     @Test
1125     public void testGroupBy() {
1126         log.info("*** testGroupBy() ***");
1127 
1128         CriteriaBuilder cb = em.getCriteriaBuilder();
1129         CriteriaQuery<Object[]> qdef = cb.createQuery(Object[].class);
1130         Root<Clerk> c = qdef.from(Clerk.class);
1131         Join<Clerk,Sale> s = c.join("sales", JoinType.LEFT);
1132 	        //select c, COUNT(s) from Clerk c
1133 	        //LEFT JOIN c.sales s
1134 	        //GROUP BY c
1135         qdef.select(cb.array(c, cb.count(s)))
1136             .groupBy(c);
1137         
1138         List<Object[]> results= em.createQuery(qdef)
1139                 				  .getResultList();
1140         for (Object[] result : results) {
1141         	log.info("found=" + Arrays.toString(result));
1142         }
1143         assertEquals("unexpected number of rows", 3, results.size());
1144     }
1145     
1146 
1147 
1148     /**
1149      * This test provides an example usage of the HAVING aggregate query
1150      * function.
1151      */
1152     @Test
1153     public void testHaving() {
1154         log.info("*** testHaving() ***");
1155         
1156         CriteriaBuilder cb = em.getCriteriaBuilder();
1157         CriteriaQuery<Object[]> qdef = cb.createQuery(Object[].class);
1158         Root<Clerk> c = qdef.from(Clerk.class);
1159         Join<Clerk,Sale> s = c.join("sales", JoinType.LEFT);
1160         
1161         //select c, COUNT(s) from Clerk c
1162         //LEFT JOIN c.sales s
1163         //GROUP BY c " +
1164         //HAVING COUNT(S) <= 1
1165         qdef.select(cb.array(c, cb.count(s)))
1166         	.groupBy(c)
1167         	.having(cb.le(cb.count(s), 1));
1168              
1169         List<Object[]> results= em.createQuery(qdef)
1170                 .getResultList();        
1171 
1172         for (Object[] result : results) {
1173             log.info("found=" + Arrays.toString(result));
1174         }
1175         assertEquals("unexpected number of rows", 2, results.size());
1176     }
1177     
1178 }