/*
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.openjpa.persistence.identity;
import java.sql.Connection;
import java.util.List;
import javax.persistence.EntityManager;
import org.apache.openjpa.persistence.OpenJPAEntityManager;
import org.apache.openjpa.persistence.OpenJPAPersistence;
import org.apache.openjpa.persistence.test.DatabasePlatform;
import org.apache.openjpa.persistence.test.SingleEMFTestCase;
/**
* Test that compound identity can consists of null component column value.
*
* This test uses pre-defined database tables created by DDL explicitly.
* The tables have <em>logical</em> compound primary keys in the sense non-null
* constraint is <em>not</em> set on the primary columns. The tables are populated
* with SQL to contain null values in these columns.
* The test verifies that results are returned as par expectation.
* For more details, refer
* <A href="https://issues.apache.org/jira/browse/OPENJPA-1397">JIRA-1397</A>
*
* @author Pinaki Poddar
* @author Michael Vorburger
*/
@DatabasePlatform("org.apache.derby.jdbc.EmbeddedDriver")
public class TestCompundIdWithNull extends SingleEMFTestCase {
private static boolean tablesCreated = false;
public void setUp() throws Exception {
// Only run on Derby because we use DDL specific to Derby
setSupportedDatabases(
org.apache.openjpa.jdbc.sql.DerbyDictionary.class);
if (isTestsDisabled()) {
return;
}
// do not use CLEAR_TABLES or DROP_TABLES
super.setUp(SimpleCompoundIdTestEntity.class, ComplexCompoundIdTestEntity.class, TypeEntity.class);
if (!tablesCreated) {
createTables(emf.createEntityManager());
tablesCreated = true;
}
}
public void testSimpleCompoundIdTestEntity() throws Exception {
EntityManager em = emf.createEntityManager();
String jpql = "SELECT o FROM SimpleCompoundIdTestEntity o ORDER BY o.secondId";
List<SimpleCompoundIdTestEntity> list = em.createQuery(jpql,SimpleCompoundIdTestEntity.class)
.getResultList();
assertEquals(2, list.size());
assertEquals(Long.valueOf(123), list.get(0).getSecondId());
SimpleCompoundIdTestEntity secondResult = list.get(1);
assertNotNull("BUG (JIRA-1397)! Result list contains null in second element", secondResult);
assertNull(secondResult.getSecondId());
em.close();
}
public void testComplexCompoundIdTestEntity() throws Exception {
EntityManager em = emf.createEntityManager();
String jpql = "SELECT o FROM ComplexCompoundIdTestEntity o ORDER BY o.type";
List<ComplexCompoundIdTestEntity> list = em.createQuery(jpql,ComplexCompoundIdTestEntity.class)
.getResultList();
assertEquals(2, list.size());
ComplexCompoundIdTestEntity secondResult = list.get(1);
assertNotNull("Result list contains null in second element", secondResult);
assertNull("Result list's second record secondId field was not null", secondResult.getType());
em.close();
}
/**
* Create tables with logical compound keys without non-null constraint.
* Populate them with null values in some of the columns.
*/
private void createTables(EntityManager em) throws Exception {
em.getTransaction().begin();
OpenJPAEntityManager kem = OpenJPAPersistence.cast(em);
Connection conn = (Connection) kem.getConnection();
// NOTE that 'logically' test_simple has a ", CONSTRAINT test_simple_pk PRIMARY KEY (firstId, secondId)",
// but at least Derby doesn't permit NULL then.. in our real-world underlying schema that leads
// to this there are *NO* PRIMARY KEY on any tables, but there is a logical model expressed
// elsewhere stating that those two columns uniquely identify a row.
try {
conn.createStatement().execute("DROP TABLE test_type");
conn.createStatement().execute("DROP TABLE test_simple");
conn.createStatement().execute("DROP TABLE test_complex");
} catch (Exception e) {
}
conn.createStatement().execute("CREATE TABLE test_simple(firstId NUMERIC, secondId NUMERIC)");
conn.createStatement().execute("INSERT INTO test_simple(firstId, secondId) VALUES (1, 123)");
conn.createStatement().execute("INSERT INTO test_simple(firstId, secondId) VALUES (1, NULL)");
conn.createStatement().execute("CREATE TABLE test_type(id NUMERIC CONSTRAINT test_type_pk PRIMARY KEY, " +
"code VARCHAR(16))");
conn.createStatement().execute("INSERT INTO test_type(id, code) VALUES (987, 'ABC')");
conn.createStatement().execute("CREATE TABLE test_complex(id NUMERIC, type_id NUMERIC)");
conn.createStatement().execute("INSERT INTO test_complex(id, type_id) VALUES (1, 987)");
conn.createStatement().execute("INSERT INTO test_complex(id, type_id) VALUES (1, NULL)");
conn.close();
em.flush();
em.getTransaction().commit();
em.close();
}
}