Ответ 1
Это сделало трюк для меня, используя hibernate как поставщик непрерывности.
@OneToOne(cascade = {CascadeType.PERSIST,CascadeType.MERGE})
У меня проблема, когда объект сопоставляется с другим объектом, который имеет прямую реализацию в своих подклассах. См. Примерное сопоставление ниже:
@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 = "М"
Когда я извлекаю местоположение с помощью диспетчера сущностей, 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)
Это сделало трюк для меня, используя hibernate как поставщик непрерывности.
@OneToOne(cascade = {CascadeType.PERSIST,CascadeType.MERGE})
Из Учебное пособие по Java EE 6 - Наследование сущностей:
Любое отображение или отношение аннотации в несобственных суперклассах игнорируются.
Итак, вы, кажется, правы, что вам нужно аннотировать класс Person
с помощью @Entity
, чтобы связать его с Location
через @OneToOne
.
Класс, обозначенный символом Аннотирование MappedSuperclass может быть отображается так же, как объект за исключением того, что будут применяться сопоставления только к его подклассам, поскольку нет таблицы существует для сопоставленного суперкласса сам по себе.
Таким образом, вы не можете использовать @MappedSuperclass
для Person, а затем сопоставить его с @OneToOne
, так как не было бы таблицы Person.
Похоже, что аннотации JPA, которые вы используете, верны. Вы пробовали предложение @Martin Klinke для значения фиктивного дискриминатора для класса Person
?
Я обнаружил, что такая проблема решает сам, если классы Entity реализуют Serializable
.
У меня было подобное сообщение об ошибке со следующей структурой:
@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;
}
Следующие изменения исправили проблему для меня:
@OneToOne
на @OneToOne(cascade = CascadeType.ALL)
@GeneratedValue
на @GeneratedValue(strategy = GenerationType.TABLE)
UPDATE: Я также обнаружил, что я не сохранял объект RealPerson, прежде чем связывать его с SomeClass. Итак, теперь, когда я сначала сначала сохраняю экземпляр, атрибут cascade
больше не требуется
Как указано в моем комментарии выше, я пробовал то же самое с 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.
Я запускаю с ним аналогичный код с несколькими отличиями. Во-первых, я помещаю класс Abstract за интерфейс. Во-вторых, я явно определяю targetEntity для отображения @OnetoOne. Примером может служить:
@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" для ясности. Потребовалось немного поиграть, чтобы заставить его работать, я надеюсь, что он решает вашу проблему.
Попробуйте добавить @ForceDiscriminator к Person. Без этой аннотации Hibernate часто пытается создать экземпляр родительского класса, игнорируя дискриминатор, который должен сказать ему, какой дочерний класс должен создать экземпляр.