mirror of https://github.com/apache/openjpa.git
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:
parent
8607e0b3b4
commit
b831319443
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
||||
// ...
|
||||
}
|
Loading…
Reference in New Issue