Наследование с помощью Java и Hibernate - приведение типов при обновлении - PullRequest
7 голосов
/ 29 марта 2019

В моих классах есть следующая иерархия

@Entity
@Table(name = "Parent")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class Parent {
}

@Entity
@DiscriminatorVlaue("FirstChild")
public class FirstChild extends Parent {
}

@Entity
@DiscriminatorVlaue("SecondChild")
public class SecondChild extends Parent {
}

Это создает таблицу Parent, как и ожидалось.

Некоторая бизнес-логика в моем приложении:

Когда запрос принят, он сохраняется как тип "Parent" и создает следующую запись в таблице

Dtype    id  value
Parent   1   "some value"

Поскольку запрос обрабатывается, он может быть типа FirstChild или типа SecondChild, поэтому в моем коде где-то у меня есть

if (some condition is met) {
// change the Parent to its firstChild type
}
else {
// chnage it to "SecondChild" type
}

Правильно ли мое понимание и использование наследования? Я, по сути, подавляю объекты в цикле if, которые генерируют исключения во время выполнения, но изменяет ли тип объекта также значение DTYPE в базе данных? По сути, я использую наследование, чтобы держать вещи организованными как их типы. Есть ли какая-то магия, которую я могу сделать в конструкторах, чтобы добиться этого? Но реальный вопрос в том, является ли Dtype изменяемым при обновлении?

Для дальнейшей работы с этим

Я создал contsructor в дочерних классах как

public FirstChild(Parent parent) {
id = parent.id
}

но это создает новую строку для подтипов,

  Dtype       id  value
  Parent      1   "some value"
  FirstChild  2   "some value"

Я проверяю, что запись "firstChild" создана с родительским идентификатором (1), но я не уверен, почему создается вторая строка

Ответы [ 3 ]

3 голосов
/ 02 апреля 2019

В реляционных базах данных нет реального наследования.Hibernate просто имитирует это.Наследование - это концепция программирования для использования других классов, например, владельца.Но вы не можете использовать другую таблицу в качестве таблицы-владельца. В дочерней таблице, если у вас есть элемент, а не родитель, но где родитель?Родитель тоже элемент .. (строка данных).Таким образом, вы моделируете это в базах данных.Hibernate имеет несколько стратегий наследования. «SINGLE_TABLE» является одной из них и собирает родительскую таблицу и дочерние таблицы в 1 таблицу.Чтобы различать, какой тип, какой класс использует 'DiscriminatorColumn' в базе данных.Этот столбец нельзя изменить, он статический и объявлен вашим классом java.Вы можете использовать DiscriminatorValue, чтобы выбрать значение для идентификации java-класса в DiscriminatorColumn.Таким образом, ваше понимание наследования отличается в реляционных базах данных.Вы должны объявить все данные дочерних строк в строках родительской таблицы ...

1 голос
/ 07 апреля 2019

Вот мои выводы:

  1. Нет никаких объективных причин, по которым Child должен расширяться Parent.С точки зрения моделирования я бы вместо этого использовал один абстрактный класс, назовем его FamilyMember, а затем Parent, FirstBorn и SecondBorn будет исходить от члена семьи.
  2. Проблема понижения будет решена с помощью (1)
  3. Hibernate не поддерживает обновление значения дискриминатора.Это означает, что если ребенок достиг совершеннолетия и уже не ребенок, а родитель.Дочерняя запись должна быть удалена, и должна быть создана новая запись, соответствующая Parent.Вот как это работает.Дочерний является дочерним, пока он больше не является дочерним, а затем дочерняя запись удаляется, и создается новая, не дочерняя, запись.
1 голос
/ 03 апреля 2019

Но на самом деле вопрос заключается в том, можно ли модифицировать Dtype при обновлении?

Нет, вы не можете: источник .

Из вашего примера ваш чистый код Java будет выглядеть так:

Parent parent = new Parent(); //object received from request, stored in database as it is
if (some conditions is met) {
   // FirstChild firstChild = (Parent) parent; //this would throw ClassCastException
   FirstChild firstChild = new FirstChild(parent); //creating new object, gc will collect parent
}

Таким образом, hibernate действует так же, как и Java: вы не можете обновить Parent, вам нужно создать новую запись для firstChild и удалить parent.

Не поможет ли вам использовать @DiscriminatorFormula вместо проверки some condition is met при обработке запроса?

@DiscriminatorFormula("case when value = 'some value' then 'FirstChild' else 'SecondChild' end")

Тогда вам не придется сохранять Parent, а затем обрабатывать его записи.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...