2011-03-08 72 views
10

當實體映射到其子實體上有直接實現的另一個實體時,我遇到問題。請參見下面的示例映射:JPA @OneToOne在映射到具有子類的抽象@實體時拋出錯誤

@Entity 
class Location { 
     @OneToOne 
     @JoinColumn(...) 
     private Person person; 
} 

@Entity 
@Inheritance(strategy=InheritanceType.SINGLE_TABLE) 
@DiscriminatorColumn(name="person_type",discriminatorType=DiscriminatorType.STRING) 
abstract class Person { 
} 

@Entity 
@DiscriminatorValue("M") 
class Man extends Person { 
    ... 
} 

@Entity 
@DiscriminatorValue("W") 
class Woman extends Person { 
    ... 
} 

現在,這是我對我的數據庫表:

位置表: ID = 1,爲person_id = 1 人表: ID = 1, person_type =「M」

當我使用實體管理器檢索位置時,hibernate會拋出一個異常,說我無法實例化抽象類或接口。

Location location = entityManager.find(Location.class, 1L); 

休眠拋出這個錯誤:

javax.persistence.PersistenceException: org.hibernate.InstantiationException: Cannot instantiate abstract class or interface: Person 
at org.hibernate.ejb.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.java:630) 
at org.hibernate.ejb.AbstractEntityManagerImpl.find(AbstractEntityManagerImpl.java:195) 
at ...... 
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
at java.lang.reflect.Method.invoke(Method.java:585) 
at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:59) 
at org.junit.internal.runners.MethodRoadie.runTestMethod(MethodRoadie.java:98) 
at org.unitils.UnitilsJUnit4TestClassRunner$TestListenerInvokingMethodRoadie.runTestMethod(UnitilsJUnit4TestClassRunner.java:174) 
at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:79) 
at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:87) 
at org.unitils.UnitilsJUnit4TestClassRunner$TestListenerInvokingMethodRoadie.runBeforesThenTestThenAfters(UnitilsJUnit4TestClassRunner.java:156) 
at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:77) 
at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:42) 
at org.unitils.UnitilsJUnit4TestClassRunner.invokeTestMethod(UnitilsJUnit4TestClassRunner.java:95) 
at org.junit.internal.runners.JUnit4ClassRunner.runMethods(JUnit4ClassRunner.java:51) 
at org.unitils.UnitilsJUnit4TestClassRunner.access$000(UnitilsJUnit4TestClassRunner.java:44) 
at org.unitils.UnitilsJUnit4TestClassRunner$1.run(UnitilsJUnit4TestClassRunner.java:62) 
at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:27) 
at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:37) 
at org.unitils.UnitilsJUnit4TestClassRunner.run(UnitilsJUnit4TestClassRunner.java:68) 
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49) 
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) 
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) 
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) 
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) 
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) 
+1

db中鑑別器列的數據類型是什麼? – 2011-03-08 19:15:18

+1

你可以顯示完整的堆棧跟蹤嗎? – axtavt 2011-03-08 19:16:04

+2

你有沒有試過@MappedSuperclass而不是@Entity on Person? – 2011-03-08 19:18:53

回答

0

正如上面我的評論指出,我試圖與EclipseLink的相同,它的工作原理。

創建了一些測試數據後,我已經清除了數據庫中人員條目的鑑別器值,現在在嘗試加載相關位置時出現類似的異常。的EclipseLink的消息是多一點點的描述:

Exception Description: Missing class for indicator field value [] of type [class java.lang.String]. 
Descriptor: RelationalDescriptor(com.mklinke.webtest.domain.Person --> [DatabaseTable(PERSON)]) 
at org.eclipse.persistence.exceptions.DescriptorException.missingClassForIndicatorFieldValue(DescriptorException.java:937) 
at org.eclipse.persistence.descriptors.InheritancePolicy.classFromValue(InheritancePolicy.java:355) 
at org.eclipse.persistence.descriptors.InheritancePolicy.classFromRow(InheritancePolicy.java:342) 
at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:485) 
at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:456) 
at org.eclipse.persistence.queries.ObjectLevelReadQuery.buildObject(ObjectLevelReadQuery.java:723) 
at org.eclipse.persistence.queries.ReadObjectQuery.registerResultInUnitOfWork(ReadObjectQuery.java:766) 
at org.eclipse.persistence.queries.ReadObjectQuery.executeObjectLevelReadQuery(ReadObjectQuery.java:451) 
at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeDatabaseQuery(ObjectLevelReadQuery.java:1080) 
at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:808) 
... 

的映射似乎工作,所以除非數據是「腐敗」(它是不是像你說的你的情況下),它可能是一個錯誤或Hibernate中至少有不同的行爲。

2

The Java EE 6 Tutorial - Entity Inheritence

Any mapping or relationship annotations in non-entity superclasses are ignored.

所以,你似乎是正確的,你必須註釋Person@Entity將其與Location通過@OneToOne關聯。

@MappedSuperclass javadoc

A class designated with the MappedSuperclass annotation can be mapped in the same way as an entity except that the mappings will apply only to its subclasses since no table exists for the mapped superclass itself.

所以你不能用在人@MappedSuperclass,然後用@OneToOne圖吧,因爲就沒有Person表。

看起來像您使用的JPA註釋是正確的。你有沒有試過@Martin Klinke對Person類的虛擬鑑別器值的建議?

+0

這解決了我的問題,我忘記了子實體上的@Entity,並收到相同的錯誤,直到我將其添加到子類。 – 2012-06-12 22:22:20

1

如果實體類實現Serializable,我發現這種問題可以解決。

0

我運行類似的代碼,有一些差異。首先,我將Abstract類放在一個接口後面。其次,我明確定義@OnetoOne映射的targetEntity。一個例子是:

@Entity 
class Location { 
    @OneToOne(targetEntity = AbstractPerson.class) 
    @JoinColumn(...) 
    private Person person; 
} 

public interface Person { 
} 

@Entity 
@Inheritance(strategy=InheritanceType.SINGLE_TABLE) 
@DiscriminatorColumn(name="person_type",discriminatorType=DiscriminatorType.STRING) 
abstract class AbstractPerson implements Person { 
} 

爲了清楚起見,我已將Person抽象類重命名爲'AbstractPerson'。花了相當多的時間來讓它工作,我希望它解決了你的問題。

0

嘗試將@ForceDiscriminator添加到Person。沒有這個註解,Hibernate經常嘗試實例化父類,忽略了應該告訴它實例化哪個子類的鑑別器。

1

我有以下結構類似的錯誤消息:

@Entity 
@Table(name = "PERSON") 
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) 
@DiscriminatorColumn(name = "TYPE", discriminatorType = DiscriminatorType.STRING) 
public abstract class Person { 

    @Id 
    @GeneratedValue 
    private Long  id; 

} 

一個具體的子實例

@Entity 
@DiscriminatorValue("REALPERSON") 
public class RealPerson extends Person{ etc... } 

,並且有一個字段引用抽象類的類:

public class SomeClass() { 
    @OneToOne 
    private Person person; 
} 

以下更改爲我解決了問題:

  1. 更改@OneToOne@OneToOne(cascade = CascadeType.ALL)
  2. 更改@GeneratedValue@GeneratedValue(strategy = GenerationType.TABLE)

更新:我也發現我沒有保存RealPerson對象將其鏈接到SomeClass的面前。所以,現在我第一次保存實例,cascade屬性不再需要

4

這對我來說,使用hibernate作爲持久性提供程序。

@OneToOne(cascade = {CascadeType.PERSIST,CascadeType.MERGE})