2011-03-08 69 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})