/***************************************************************** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * <p/> * http://www.apache.org/licenses/LICENSE-2.0 * <p/> * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. ****************************************************************/ package org.apache.cayenne.query; import org.apache.cayenne.DataRow; import org.apache.cayenne.QueryResponse; import org.apache.cayenne.access.DataContext; import org.apache.cayenne.di.Inject; import org.apache.cayenne.log.JdbcEventLogger; import org.apache.cayenne.test.jdbc.DBHelper; import org.apache.cayenne.test.jdbc.TableHelper; import org.apache.cayenne.testdo.testmap.Artist; import org.apache.cayenne.testdo.testmap.Painting; import org.apache.cayenne.tx.BaseTransaction; import org.apache.cayenne.tx.ExternalTransaction; import org.apache.cayenne.unit.UnitDbAdapter; import org.apache.cayenne.unit.di.server.CayenneProjects; import org.apache.cayenne.unit.di.server.ServerCase; import org.apache.cayenne.unit.di.server.UseServerRuntime; import org.junit.Test; import java.math.BigDecimal; import java.util.List; import static org.hamcrest.CoreMatchers.instanceOf; import static org.junit.Assert.*; @UseServerRuntime(CayenneProjects.TESTMAP_PROJECT) public class MappedQueryIT extends ServerCase { @Inject private DataContext context; @Inject private DBHelper dbHelper; @Inject private UnitDbAdapter accessStackAdapter; @Inject private JdbcEventLogger jdbcEventLogger; protected void createArtistsDataSet() throws Exception { TableHelper tArtist = new TableHelper(dbHelper, "ARTIST"); tArtist.setColumns("ARTIST_ID", "ARTIST_NAME", "DATE_OF_BIRTH"); long dateBase = System.currentTimeMillis(); for (int i = 1; i <= 20; i++) { tArtist.insert(i, "artist" + i, new java.sql.Date(dateBase + 10000 * i)); } } @Test public void testSelectQuery() throws Exception { createArtistsDataSet(); Artist a = MappedSelect.query("ParameterizedQueryWithLocalCache", Artist.class) .param("name", "artist14").select(context).get(0); assertNotNull(a); assertEquals("artist14", a.getArtistName()); } @Test public void testSQLTemplateSelect() throws Exception { createArtistsDataSet(); List<DataRow> result = MappedSelect.query("SelectTestLower", DataRow.class).select(context); assertEquals(20, result.size()); assertThat(result.get(0), instanceOf(DataRow.class)); } @Test public void testSQLTemplateUpdate() throws Exception { int updated = MappedExec.query("NonSelectingQuery").update(context)[0]; assertEquals(1, updated); Painting painting = ObjectSelect.query(Painting.class).selectOne(context); assertEquals("No Painting Like This", painting.getPaintingTitle()); assertEquals(12.5, painting.getEstimatedPrice().doubleValue(), 0); } @Test public void testProcedureQuery() throws Exception { if (!accessStackAdapter.supportsStoredProcedures()) { return; } if (!accessStackAdapter.canMakeObjectsOutOfProcedures()) { return; } // create an artist with painting in the database Artist a = context.newObject(Artist.class); a.setArtistName("An Artist"); Painting p = context.newObject(Painting.class); p.setPaintingTitle("A Painting"); // converting double to string prevents rounding weirdness... p.setEstimatedPrice(new BigDecimal(1000)); a.addToPaintingArray(p); context.commitChanges(); List<?> artists = runProcedureSelect(MappedSelect.query("ProcedureQuery", Artist.class) .param("aName", "An Artist") .param("paintingPrice", 3000).forceNoCache()).firstList(); // check the results assertNotNull("Null result from StoredProcedure.", artists); assertEquals(1, artists.size()); Artist artistRow = (Artist) artists.get(0); assertEquals("An Artist", artistRow.getArtistName()); } @Test public void testEJBQLQuery() throws Exception { createArtistsDataSet(); List result = MappedSelect.query("EjbqlQueryTest").select(context); assertEquals(20, result.size()); assertThat(result.get(0), instanceOf(DataRow.class)); } @Test public void testCacheKey() { // ensure queries initialized with different parameters receive different cache keys MappedSelect<Artist> query1 = MappedSelect .query("ParameterizedQueryWithLocalCache", Artist.class).param("name", "artist1"); MappedSelect<Artist> query2 = MappedSelect .query("ParameterizedQueryWithLocalCache", Artist.class).param("name", "artist2"); MappedSelect<Artist> query3 = MappedSelect .query("ParameterizedQueryWithLocalCache", Artist.class).param("name", "artist2"); assertNotEquals( query1.getMetaData(context.getEntityResolver()).getCacheKey(), query2.getMetaData(context.getEntityResolver()).getCacheKey()); assertEquals( query2.getMetaData(context.getEntityResolver()).getCacheKey(), query3.getMetaData(context.getEntityResolver()).getCacheKey()); } protected QueryResponse runProcedureSelect(AbstractMappedQuery q) throws Exception { // Sybase blows whenever a transaction wraps a SP, so turn off // transactions // TODO: it is quite the opposite with PostgreSQL. If an SP returns an // open refcursor, it actually expects a TX in progress, so while we // don't have refcursor unit tests, this is something to keep in mind // e.g. // http://stackoverflow.com/questions/16921942/porting-apache-cayenne-from-oracle-to-postgresql BaseTransaction t = new ExternalTransaction(jdbcEventLogger); BaseTransaction.bindThreadTransaction(t); try { return context.performGenericQuery(q); } finally { BaseTransaction.bindThreadTransaction(null); t.commit(); } } }