OPENJPA-931: IdClass support

git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@748349 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Fay Wang 2009-02-26 23:35:54 +00:00
parent 4d28f28b20
commit b811a6c43b
12 changed files with 649 additions and 9 deletions

View File

@ -656,8 +656,10 @@ public class FieldMapping
//The name of the attribute within the composite key to which
//the relationship attribute corresponds.
Object target = ((ObjectId)sm.getObjectId()).getId();
if (target == null)
return;
setMappedByIdValue(target, pkVal, mappedByIdFieldName);
pkVal = target;
pkVal = target;
}
sm.storeObjectField(fmds[0].getIndex(), pkVal);
}

View File

@ -194,6 +194,7 @@ public class ClassMetaData
private FetchGroup[] _fgs = null;
private FetchGroup[] _customFGs = null;
private boolean _intercepting = false;
private Boolean _useIdClassFromParent = null;
/**
* Constructor. Supply described type and repository.
@ -439,8 +440,17 @@ public class ClassMetaData
* The metadata-specified class to use for the object ID.
*/
public Class getObjectIdType() {
if (_objectId != null)
return _objectId;
// if this entity does not use IdClass from the parent entity,
// just return the _objectId set during annotation parsing time.
if (!useIdClassFromParent()) {
if (_objectId != null)
return _objectId;
}
// if this entity uses IdClass from the parent entity,
// the _objectId set during the parsing time should be
// ignored, and let Openjpa determine the objectId type
// of this entity.
if (getIdentityType() != ID_APPLICATION)
return null;
ClassMetaData sup = getPCSuperclassMetaData();
@ -504,6 +514,13 @@ public class ClassMetaData
/**
* The metadata-specified class to use for the object ID.
* When there is IdClass annotation, AnnotationMetaDataParser
* will call this method to set ObjectId type. However, if
* this is a derived identity in the child entity where a
* relation field (parent entity) is used as an id, and this
* relation field has an IdClass, the IdClass annotation in
* the child entity can be ignored as Openjpa will automatically
* wrap parent's IdClass as child's IdClass.
*/
public void setObjectIdType(Class cls, boolean shared) {
_objectId = null;
@ -1904,6 +1921,45 @@ public class ClassMetaData
validateAppIdClassPKs(this, pks, _objectId);
}
}
/**
* Return true if this class uses IdClass derived from idClass of the
* parent entity which annotated as id in the child class.
* In this case, there are no key fields in the child entity corresponding
* to the fields in the IdClass.
*/
public boolean useIdClassFromParent() {
if (_useIdClassFromParent == null) {
if (_objectId == null)
_useIdClassFromParent = false;
else {
FieldMetaData[] pks = getPrimaryKeyFields();
if (pks.length != 1)
_useIdClassFromParent = false;
else {
ClassMetaData pkMeta = pks[0].getTypeMetaData();
if (pkMeta == null)
_useIdClassFromParent = false;
else {
Class pkType = pkMeta.getObjectIdType();
if (pkType == ObjectId.class) //parent id is EmbeddedId
pkType = pkMeta.getPrimaryKeyFields()[0].getType();
if (pkType == _objectId)
_useIdClassFromParent = true;
else {
Field f = Reflection.findField(_objectId,
pks[0].getName(), false);
if (f != null)
_useIdClassFromParent = false;
else
throw new MetaDataException(_loc.get("invalid-id",
_type, pks[0].getName()));
}
}
}
}
}
return _useIdClassFromParent.booleanValue();
}
/**
* Return true if this class has a concrete persistent superclass.

View File

@ -504,6 +504,8 @@ public class ApplicationIds {
key = ((ObjectId)id).getId();
Object val = null;
if (mappedByIdFieldName.length() != 0) {
if (((ObjectId)id).getId() == null)
return false;
Class idClass = ((ObjectId)id).getId().getClass();
val = Reflection.get(key,
Reflection.findField(idClass, mappedByIdFieldName, true));

View File

@ -21,6 +21,7 @@ package org.apache.openjpa.persistence.enhance.identity;
import javax.persistence.*;
@Entity
@Table(name="MED2_MBI")
public class MedicalHistory2 {
@Id
long id;

View File

@ -0,0 +1,68 @@
/*
* 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.enhance.identity;
import javax.persistence.*;
@Entity
@Table(name="MED3_MBI")
@IdClass(PersonId3.class)
public class MedicalHistory3 {
String name;
@Id
@OneToOne Person3 patient;
public Person3 getPatient() {
return patient;
}
public void setPatient(Person3 p) {
this.patient = p;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean equals(Object o) {
if (o == null) return false;
if (!(o instanceof MedicalHistory3)) return false;
MedicalHistory3 m0 = (MedicalHistory3)o;
String name0 = m0.getName();
if (name != null && !name.equals(name0)) return false;
if (name == null && name0 != null) return false;
Person3 p0 = m0.getPatient();
if (patient != null && !patient.equals(p0)) return false;
if (patient == null && p0 != null) return false;
return true;
}
public int hashCode() {
int ret = 0;
ret = ret * 31 + name.hashCode();
//ret = ret * 31 + patient.hashCode();
return ret;
}
}

View File

@ -0,0 +1,69 @@
/*
* 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.enhance.identity;
import javax.persistence.*;
@Entity
@Table(name="MED4_MBI")
@IdClass(PersonId4.class)
public class MedicalHistory4 {
String name;
@Id
@OneToOne Person4 patient;
public Person4 getPatient() {
return patient;
}
public void setPatient(Person4 p) {
this.patient = p;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean equals(Object o) {
if (o == null) return false;
if (!(o instanceof MedicalHistory4)) return false;
MedicalHistory4 m0 = (MedicalHistory4)o;
String name0 = m0.getName();
if (name != null && !name.equals(name0)) return false;
if (name == null && name0 != null) return false;
Person4 p0 = m0.getPatient();
if (patient != null && !patient.equals(p0)) return false;
if (patient == null && p0 != null) return false;
return true;
}
public int hashCode() {
int ret = 0;
ret = ret * 31 + name.hashCode();
ret = ret * 31 + patient.id.firstName.hashCode();
ret = ret * 31 + patient.id.lastName.hashCode();
return ret;
}
}

View File

@ -21,6 +21,7 @@ package org.apache.openjpa.persistence.enhance.identity;
import javax.persistence.*;
@Entity
@Table(name="PER2_MBI")
public class Person2 {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)

View File

@ -0,0 +1,83 @@
/*
* 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.enhance.identity;
import javax.persistence.*;
@Entity
@Table(name="PER3_MBI")
@IdClass(PersonId3.class)
public class Person3 {
@Id
String firstName;
@Id
String lastName;
@OneToOne(mappedBy="patient")
MedicalHistory3 medical;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public MedicalHistory3 getMedical() {
return medical;
}
public void setMedical(MedicalHistory3 medical) {
this.medical = medical;
}
public boolean equals(Object o) {
if (o == null) return false;
if (!(o instanceof Person3)) return false;
Person3 p0 = (Person3)o;
String firstName0 = p0.getFirstName();
String lastName0 = p0.getLastName();
MedicalHistory3 medical0 = p0.getMedical();
if (!firstName.equals(firstName0)) return false;
if (!lastName.equals(lastName0)) return false;
if (medical != null && medical0 != null && !medical.name.equals(medical0.name)) return false;
if (medical == null && medical0 != null) return false;
if (medical != null && medical0 == null) return false;
return true;
}
public int hashCode() {
int ret = 0;
ret = ret * 31 + firstName.hashCode();
ret = ret * 31 + lastName.hashCode();
if (medical != null)
ret = ret * 31 + medical.hashCode();
return ret;
}
}

View File

@ -0,0 +1,71 @@
/*
* 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.enhance.identity;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.OneToOne;
import javax.persistence.Table;
@Entity
@Table(name="PER4_MBI")
public class Person4 {
@EmbeddedId
PersonId4 id;
@OneToOne(mappedBy="patient")
MedicalHistory4 medical;
public PersonId4 getId() {
return id;
}
public void setId(PersonId4 id) {
this.id = id;
}
public MedicalHistory4 getMedical() {
return medical;
}
public void setMedical(MedicalHistory4 medical) {
this.medical = medical;
}
public boolean equals(Object o) {
if (o == null) return false;
if (!(o instanceof Person4)) return false;
Person4 p0 = (Person4)o;
PersonId4 id0 = p0.getId();
if (!id.equals(id0)) return false;
MedicalHistory4 medical0 = p0.getMedical();
if (medical != null &&
!medical.patient.getId().equals(medical0.patient.getId())) return false;
if (medical == null && medical0 != null) return false;
return true;
}
public int hashCode() {
int ret = 0;
ret = ret * 31 + id.hashCode();
if (medical != null)
ret = ret * 31 + medical.hashCode();
return ret;
}
}

View File

@ -0,0 +1,70 @@
/*
* 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.enhance.identity;
public class PersonId3 {
String firstName;
String lastName;
public PersonId3() {}
public PersonId3(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getFirstName() {
return firstName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getLastName() {
return lastName;
}
public boolean equals(Object o) {
if (o == null) return false;
if (!(o instanceof PersonId3)) return false;
PersonId3 eid = (PersonId3)o;
String firstName0 = eid.getFirstName();
String lastName0 = eid.getLastName();
if (firstName != null && !firstName.equals(firstName0)) return false;
if (firstName == null && firstName0 != null) return false;
if (lastName != null && !lastName.equals(lastName0)) return false;
if (lastName == null && lastName0 != null) return false;
return true;
}
public int hashCode() {
int ret = 0;
if (firstName != null)
ret = ret * 31 + firstName.hashCode();
if (lastName != null)
ret = ret * 31 + lastName.hashCode();
return ret;
}
}

View File

@ -0,0 +1,73 @@
/*
* 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.enhance.identity;
import javax.persistence.*;
@Embeddable
public class PersonId4 {
String firstName;
String lastName;
public PersonId4() {}
public PersonId4(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getFirstName() {
return firstName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getLastName() {
return lastName;
}
public boolean equals(Object o) {
if (o == null) return false;
if (!(o instanceof PersonId4)) return false;
PersonId4 eid = (PersonId4)o;
String firstName0 = eid.getFirstName();
String lastName0 = eid.getLastName();
if (firstName != null && !firstName.equals(firstName0)) return false;
if (firstName == null && firstName0 != null) return false;
if (lastName != null && !lastName.equals(lastName0)) return false;
if (lastName == null && lastName0 != null) return false;
return true;
}
public int hashCode() {
int ret = 0;
if (firstName != null)
ret = ret * 31 + firstName.hashCode();
if (lastName != null)
ret = ret * 31 + lastName.hashCode();
return ret;
}
}

View File

@ -49,6 +49,11 @@ public class TestMappedById extends SingleEMFTestCase {
public Map<String, Person2> persons2 = new HashMap<String, Person2>();
public Map<String, MedicalHistory2> medicals2 =
new HashMap<String, MedicalHistory2>();
public Map<String, Person3> persons3 = new HashMap<String, Person3>();
public Map<String, MedicalHistory3> medicals3 = new HashMap<String,
MedicalHistory3>();
public Map<String, Person4> persons4 = new HashMap<String, Person4>();
public Map<String, MedicalHistory4> medicals4 = new HashMap<String, MedicalHistory4>();
public Map<Integer, Employee3> emps3 = new HashMap<Integer, Employee3>();
public Map<Object, Dependent3> depMap3 =
@ -66,14 +71,20 @@ public class TestMappedById extends SingleEMFTestCase {
public int mId1 = 1;
public int pId2 = 1;
public int mId2 = 1;
public int pId3 = 1;
public int mId3 = 1;
public int pId4 = 1;
public int mId4 = 1;
public void setUp() throws Exception {
super.setUp(DROP_TABLES, Dependent1.class, Employee1.class,
DependentId1.class, Dependent2.class, Employee2.class,
DependentId2.class, EmployeeId2.class, MedicalHistory1.class,
Person1.class, PersonId1.class, MedicalHistory2.class,
Person2.class, Dependent3.class, Employee3.class,
DependentId3.class, Parent3.class);
Person2.class, Person3.class, MedicalHistory3.class,
Person4.class, PersonId4.class, MedicalHistory4.class,
Dependent3.class, Employee3.class, DependentId3.class,
Parent3.class);
}
/**
@ -122,6 +133,24 @@ public class TestMappedById extends SingleEMFTestCase {
queryObj5();
}
/**
* This is spec 2.4.1.2 Example 5, case(a)
*/
public void testMappedById6() {
createObj6();
findObj6();
queryObj6();
}
/**
* This is spec 2.4.1.2 Example 6, case(a)
*/
public void testMappedById7() {
createObj7();
findObj7();
queryObj7();
}
public void createObj1() {
EntityManager em = emf.createEntityManager();
EntityTransaction tran = em.getTransaction();
@ -377,7 +406,7 @@ public class TestMappedById extends SingleEMFTestCase {
EntityManager em = emf.createEntityManager();
Person2 p = em.find(Person2.class, ssn);
Person2 p1 = p.getMedical().getPatient();
Assert.assertEquals(p1, p);
assertEquals(p1, p);
}
public void queryObj4() {
@ -418,9 +447,8 @@ public class TestMappedById extends SingleEMFTestCase {
String name = m.getName();
MedicalHistory2 m0 = medicals2.get(name);
MedicalHistory2 m1 = m.getPatient().getMedical();
Assert.assertEquals(m1, m);
assertEquals(m1, m);
}
public void createObj5() {
EntityManager em = emf.createEntityManager();
@ -436,7 +464,6 @@ public class TestMappedById extends SingleEMFTestCase {
depMap3.put(did.getId(), d);
}
em.close();
}
@ -497,4 +524,121 @@ public class TestMappedById extends SingleEMFTestCase {
assertEquals(d0, d);
}
public void createObj6() {
EntityManager em = emf.createEntityManager();
EntityTransaction tran = em.getTransaction();
for (int i = 0; i < numPersons; i++)
createPerson3(em, pId3++);
tran.begin();
em.flush();
tran.commit();
em.close();
}
public Person3 createPerson3(EntityManager em, int id) {
Person3 p = new Person3();
p.setFirstName("f_" + id);
p.setLastName("l_" + id);
MedicalHistory3 m = createMedicalHistory3(em, mId3++);
m.setPatient(p);
p.setMedical(m);
em.persist(m);
em.persist(p);
persons3.put(p.getFirstName(), p);
medicals3.put(m.getPatient().getFirstName(), m);
return p;
}
public MedicalHistory3 createMedicalHistory3(EntityManager em, int id) {
MedicalHistory3 m = new MedicalHistory3();
m.setName("medical_" + id);
return m;
}
public void findObj6() {
EntityManager em = emf.createEntityManager();
Person3 p = em.find(Person3.class, new PersonId3("f_1", "l_1"));
Person3 p0 = persons3.get("f_1");
Person3 p1 = p.getMedical().getPatient();
assertEquals(p, p1);
}
public void queryObj6() {
EntityManager em = emf.createEntityManager();
EntityTransaction tran = em.getTransaction();
tran.begin();
String firstName = "f_1";
String jpql = "select m from MedicalHistory3 m where m.patient.firstName = '" + firstName + "'";
Query q = em.createQuery(jpql);
List<MedicalHistory3> ms = q.getResultList();
for (MedicalHistory3 m : ms) {
assertMedicalHistory3(m, firstName);
}
tran.commit();
em.close();
}
public void assertMedicalHistory3(MedicalHistory3 m, String firstName) {
MedicalHistory3 m0 = medicals3.get(firstName);
assertEquals(m0, m);
}
public void createObj7() {
EntityManager em = emf.createEntityManager();
EntityTransaction tran = em.getTransaction();
for (int i = 0; i < numPersons; i++)
createPerson4(em, pId4++);
tran.begin();
em.flush();
tran.commit();
em.close();
}
public Person4 createPerson4(EntityManager em, int id) {
Person4 p = new Person4();
p.setId(new PersonId4("f_" + id, "l_" + id));
MedicalHistory4 m = createMedicalHistory4(em, mId4++);
m.setPatient(p);
p.setMedical(m);
em.persist(p);
em.persist(m);
persons4.put(p.getId().getFirstName(), p);
medicals4.put(m.getPatient().getId().getFirstName(), m);
return p;
}
public MedicalHistory4 createMedicalHistory4(EntityManager em, int id) {
MedicalHistory4 m = new MedicalHistory4();
m.setName("medical_" + id);
return m;
}
public void findObj7() {
EntityManager em = emf.createEntityManager();
Person4 p = em.find(Person4.class, new PersonId4("f_1", "l_1"));
Person4 p0 = persons4.get("f_1");
Person4 p1 = p.getMedical().getPatient();
assertEquals(p1, p);
}
public void queryObj7() {
EntityManager em = emf.createEntityManager();
EntityTransaction tran = em.getTransaction();
tran.begin();
String firstName = "f_1";
String jpql = "select m from MedicalHistory4 m where m.patient.id.firstName = '" + firstName + "'";
Query q = em.createQuery(jpql);
List<MedicalHistory4> ms = q.getResultList();
for (MedicalHistory4 m : ms) {
assertMedicalHistory4(m, firstName);
}
tran.commit();
em.close();
}
public void assertMedicalHistory4(MedicalHistory4 m, String firstName) {
MedicalHistory4 m0 = medicals4.get(firstName);
MedicalHistory4 m1 = m.getPatient().getMedical();
assertEquals(m1, m);
}
}