11

エンティティが、そのサブクラスに直接実装されている別のエンティティにマップされているときに問題が発生します。以下のサンプルマッピングを参照してください。

@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 {
    ...
}

さて、これは私が私のデータベーステーブルに持っているものです:

location-table:id = 1、person_id = 1 person-table:id = 1、person_type = "M"

エンティティマネージャーを使用してロケーションを取得すると、hibernateは、抽象クラスまたはインターフェイスをインスタンス化できないという例外をスローします。

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

Hibernateはこのエラーをスローします:

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)
4

7 に答える 7

4

これは、休止状態を永続化プロバイダーとして使用して、私にとってはうまくいきました。

@OneToOne(cascade = {CascadeType.PERSIST,CascadeType.MERGE}) 
于 2012-09-28T09:12:58.660 に答える
2

From The Java EE 6 Tutorial - Entity Inheritence:

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

So you seem to be correct that you have to annotate the Person class with @Entity to associate it with a Location via @OneToOne.

From the @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.

So you couldn't use @MappedSuperclass on Person, then map it with the @OneToOne, since there would be no Person table.

Seems like the JPA annotations you are using are correct. Have you tried @Martin Klinke's suggestion of a dummy discriminator value for the Person class?

于 2011-03-09T13:57:03.500 に答える
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属性は不要になりました

于 2012-03-01T15:13:59.983 に答える
1

この種の問題は、Entity クラスが を実装すると自然に解決することがわかりましたSerializable

于 2011-03-09T23:39:07.053 に答える
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」に変更しました。それを機能させるためにかなりの遊びをしました、それがあなたの問題を解決することを願っています。

于 2011-03-29T11:59:57.650 に答える
0

@ForceDiscriminator を Person に追加してみてください。このアノテーションがないと、Hibernate は多くの場合、どの子クラスをインスタンス化するかを指示する識別子を無視して、親クラスをインスタンス化しようとします。

于 2011-06-13T15:22:32.460 に答える
0

上記のコメントに示されているように、EclipseLink でも同じことを試してみましたが、うまくいきました。

いくつかのテスト データを作成した後、DB 内の person エントリの識別子の値をクリアしました。関連する場所を読み込もうとすると、同様の例外が発生します。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 の動作が異なります。

于 2011-03-08T22:21:52.580 に答える