OPENJPA-1397: Allow some columns of compound key to be null.

git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@888418 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Pinaki Poddar 2009-12-08 14:52:17 +00:00
parent 8607e0b3b4
commit b831319443
6 changed files with 384 additions and 0 deletions

View File

@ -0,0 +1,58 @@
/*
* 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 javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
/**
* JPA Entity with a compound Id of two fields, one simple and one an Entity.
*
* @author Michael Vorburger
*/
@Entity
@Table(name = "test_complex")
@IdClass(ComplexCompoundIdTestEntityId.class)
public class ComplexCompoundIdTestEntity {
@Id
@Column(nullable = false)
private Long id;
@Id
@ManyToOne(cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH },
fetch = FetchType.LAZY, optional = true)
@JoinColumn(nullable = true, name = "type_id")
private TypeEntity type;
public Long getId() {
return id;
}
public TypeEntity getType() {
return type;
}
}

View File

@ -0,0 +1,63 @@
/*
* 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;
/**
* JPA Id for ComplexCompoundIdTestEntity.
*
* @author Michael Vorburger
*/
public class ComplexCompoundIdTestEntityId {
private Long id;
private Long type;
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((type == null) ? 0 : type.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ComplexCompoundIdTestEntityId other = (ComplexCompoundIdTestEntityId) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
if (type == null) {
if (other.type != null)
return false;
} else if (!type.equals(other.type))
return false;
return true;
}
}

View File

@ -0,0 +1,56 @@
/*
* 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 javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.Table;
/**
* JPA Entity with a compound Id of two fields, both simple.
*
* @author Michael Vorburger
*/
@Entity
@Table(name = "test_simple")
@IdClass(SimpleCompoundIdTestEntityId.class)
public class SimpleCompoundIdTestEntity {
@Id
@Column(nullable = false)
private Long firstId;
@Id
@Column(nullable = true)
private Long secondId;
// ...
public Long getFirstId() {
return firstId;
}
public Long getSecondId() {
return secondId;
}
// ...
}

View File

@ -0,0 +1,64 @@
/*
* 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;
/**
* JPA Id for SimpleCompoundIdTestEntity.
*
* @author Michael Vorburger
*/
public class SimpleCompoundIdTestEntityId {
public Long firstId;
public Long secondId;
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((firstId == null) ? 0 : firstId.hashCode());
result = prime * result + ((secondId == null) ? 0 : secondId.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
SimpleCompoundIdTestEntityId other = (SimpleCompoundIdTestEntityId) obj;
if (firstId == null) {
if (other.firstId != null)
return false;
} else if (!firstId.equals(other.firstId))
return false;
if (secondId == null) {
if (other.secondId != null)
return false;
} else if (!secondId.equals(other.secondId))
return false;
return true;
}
}

View File

@ -0,0 +1,121 @@
/*
* 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.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
*/
public class TestCompundIdWithNull extends SingleEMFTestCase {
private static boolean tablesCreated = false;
public void setUp() throws Exception {
// do not use CLEAR_TABLES or DROP_TABLES
super.setUp(SimpleCompoundIdTestEntity.class, ComplexCompoundIdTestEntity.class, TypeEntity.class);
if (!tablesCreated) {
createTables(emf.createEntityManager());
}
}
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();
}
}

View File

@ -0,0 +1,22 @@
package org.apache.openjpa.persistence.identity;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
/**
* JPA Entity
*
* @author Michael Vorburger
*/
@Entity
@Table(name = "test_type")
public class TypeEntity {
@Id
private Long id;
private String code;
// ...
}