Наследование JPA

#java #hibernate #inheritance #jpa #toplink

#java #переход в спящий режим #наследование #jpa #toplink

Вопрос:

Привет, я новичок в JPA, и у меня возникли проблемы с пониманием того, как он обрабатывает наследование.

У меня есть конкретная проблема, которую мне нужно решить без изменения схемы БД, но если вы не можете найти решение, я был бы признателен за предложения по решению с другой схемой БД (приветствуются решения Hibernate / TopLink).

Если я был неясен или вам нужна дополнительная информация, пожалуйста, скажите мне об этом. Заранее спасибо!

У меня есть эта база данных:

 TABLE Fruit
Id Varchar (10) Primary Key
size Varchar (10)
fruit_type Varchar(10)

TABLE Apple
Id Varchar (10) Primary Key Foreign Key references Fruit.Id
Apple_Property Varchar(10)
  

Пока что мои объекты выглядят следующим образом :

 @Entity
@Inheritance(strategy=InheritanceType.JOINED)
@DiscriminatorColumn(name="fruit_type", discriminatorType=DiscriminatorType.Char)
@DiscriminatorValue(value="fruit")

public class Fruit implements Serializable {

    @Id
    protected String Id;

    protected String size;
}

@Entity
@DiscriminatorValue(value="apple")
//@PrimaryKeyJoinColumn(name="Id" , referencedColumnName="Id")

public class Apple extends Fruit implements Serializable {

    private String Apple_Property;
}
  

В настоящее время я могу сохранять объекты Fruit без проблем..
Объекты Apple сохраняются только тогда, когда их объект Fruit еще не был сохранен.

Если я попытаюсь сохранить объект apple с уже сохраненным объектом Fruit :

 Fruit fruit1 = new Fruit("1", "Small");
Apple apple1 = new Apple(fruit1, "red");
provider.create(fruit1);
provider.create(apple1);
  

Я получу сообщение об ошибке, поскольку JPA пытается создать новую строку в таблице Fruit с Id = «1»
которое уже существует.

..

Ответ №1:

При использовании JPA для сохранения дочернего объекта (т.е. provider.create(apple1) в вашем случае) в дочернюю таблицу и все ее родительские таблицы будет вставлена запись. Таким образом, provider.create(apple1) будет вставлена запись в the Fruit и запись в таблицу Apple.

В вашем примере, если вы хотите сохранить только объект Apple, достаточно просто вызвать provider.create(apple1) . Ссылка на fruit также будет сохранена внутри объекта Apple.

Кстати, я предлагаю, чтобы PK в таблице Fruit имел числовой тип и использовался @GeneratedValue для обозначения поля ID компонента Fruit. Таким образом, вы можете позволить базе данных генерировать идентификатор для вас, и вам больше не нужно устанавливать его явно в коде Java, чтобы избежать этой ошибки «Идентификатор уже существует» из-за установки уже существующего идентификатора в коде Java.

Комментарии:

1. Спасибо за ваш ответ! Но .. мне нужно иметь возможность сохранять fruit1 и позже создавать объект apple из этого fruit1… Но при этом я получаю дублирующуюся ошибку первичного ключа .. сохраняющийся fruit1 позже запишет в таблицу значения Fruit (1, Small, Fruit), при сохранении apple1 он вставляет значения (1, red) в таблицу Apple, но вылетает при попытке снова вставить значения (1, Small, Fruit) в таблицу Fruit

2. При первом сохранении fruit1 вы должны сохранить его как объект apple вместо объекта fruit . Таким образом, записи с присвоенным вами идентификатором будут вставлены как в таблицу fruit, так и в таблицу apple . Затем, после того как вы узнаете свойства объекта Apple позже, вы извлекаете объект Apple из базы данных, используя идентификатор, и обновляете его значение.

Ответ №2:

Я думаю, что это работает именно так, как задумано. Когда вы используете объединенное наследование и сохраняете объект apple, JPA автоматически вставит его как в таблицы apple, так и в таблицы fruit. Вам не нужно моделировать дополнительное отношение или объединенный столбец в ваших классах сущностей.

Ответ №3:

Вы пытаетесь использовать концепцию наследования Java при создании таблиц db, что в данном случае несколько невозможно. Я мог бы придумать другой подход к этой проблеме. Есть таблица fruit_type и fruit. fruit_type(идентификатор, имя_типа, описание) fruit(идентификатор, имя, type_id, описание) здесь type_id будет внешним ключом.

Комментарии:

1. Это возможно в JPA. Смотрите : wiki.eclipse.org/EclipseLink/Examples/JPA /…

Ответ №4:

У меня такая же проблема, и пока единственным способом, который я нашел, было запросить родительский элемент и создать дочерний элемент с помощью parent. Затем удалите родительский элемент и воссоздайте обе записи заново.