Гибернационный полиморфизм - PullRequest
12 голосов
/ 11 июня 2009

Это вопрос Hibnerate полиморфизма и дизайн модели данных вопрос; они переплетены. Я использовал Hibernate в прошлом, и наслаждался этим, но иногда мне трудно думать ни о чем, кроме тривиальных замыслов. Не стучите в спящий режим; просто наблюдение, что ORM в целом может быть сложным.

Я думаю, что это вопрос Hibernate 101, но я не уверен. То, чего я пытаюсь достичь, может даже оказаться невозможным.

У меня есть абстрактный класс Fruit, который будет разделен на Apple и оранжевый. У меня есть класс Note, который представляет заметки или комментарии о яблоках и апельсинах. Яблоко или апельсин могут иметь много нот связано с ним, но когда-либо будет только один Apple или Orange связанных с данной запиской.

Вот эскизы классов, где я пока опускаю, где Идентификатор объекта, и свойства яблок, которые различают их из апельсинов. В настоящее время я не очень уверен в том, какую стратегию наследования Hibernate я использую.

abstract public class Fruit {
}

// Apples have notes written about them:
public class Apple extends Fruit {
   private Set<Note> note;
   ...

   @OneToMany(cascade = CascadeType.ALL)
   public Set<Note> getNote() {
       return note;
   }
}


// Oranges have notes written about them:
public class Orange extends Fruit {
   private Set<Note> note;
   ...

   @OneToMany(cascade = CascadeType.ALL)
   public Set<Note> getNote() {
       return note;
   }
}

Здесь реализован класс Note, в котором мы видим, что у него есть поля для Apple и Orange. Недостаток или несоответствие в этом дизайне, что один экземпляр заметки будет указывать только на один из Apple или Orange, и никогда не оба. Так что, если примечание связано с Яблоко, оранжевое поле лишнее и неприглядное, и семафоре.

// A note about an Apple or Orange
public class Note {
   private String theNote;
   private Apple apple; 
   private Orange orange;
   ...

   // with the usual many to one mapping
   @ManyToOne
   @JoinColumn(name = "apple_id")
   public Apple getApple() { 
       return apple;
   }

   // with the usual many to one mapping
   @ManyToOne
   @JoinColumn(name = "orange_id")
   public Orange getOrange() {
       return orange;
   }

   ...
}

Однако, это класс Note, который я думаю Я хочу основать свой дизайн, но я не уверен, как относиться к этому с уважением в спящий аннотации и отображение таблиц:

// A note about a fruit:
public class Note {
   private String theNote;
   private Fruit fruit;
   ...
}

, тогда фрукт будет экземпляром Apple или Orange.

Может ли последний класс Note со ссылкой на Fruit, который фактически будет содержать Apple или Orange, даже согласовываться с отображением Hibernate ORM? Если да, может кто-нибудь рассказать о том, как.

Ответы [ 2 ]

15 голосов
/ 12 июня 2009

Это абсолютно возможно. Вы можете связать примечания с абстрактным классом Fruit вместо того, чтобы повторять их в каждой из реализаций:

@Entity
@Inheritance
public abstract class Fruit {
   private Set<Note> notes;
   ...

   @OneToMany(cascade = CascadeType.ALL, mappedBy = "fruit")
   public Set<Note> getNotes() {
       return notes;
   }
}

@Entity
public class Apple extends Fruit {
   ...
}


@Entity
public class Orange extends Fruit {
   ...
}

@Entity
public class Note {
   private String theNote;

   @ManyToOne
   private Fruit fruit;
   ...
}

Ét voilà!

- Дополнение на основе комментария: JPA предоставляет несколько стратегий для работы с наследованием. соответствующий раздел в руководстве по Java EE должен помочь вам начать работу.

В основном, ваши варианты:

  • Хранение всего в одной таблице и использование столбца дискриминатора, чтобы узнать, какая строка какого типа
  • Хранение каждого конкретного класса (Apple и Orange) в отдельной таблице
  • Наличие общей таблицы Fruit с колонкой дискриминатора и таблиц Apple и Orange с внешним ключом для таблицы Fruit

Другое редактирование: Заметил, что это Hibernate, а не вопрос JPA. Тем не менее, не имеет большого значения, так как варианты одинаковы. Вот соответствующий раздел в документах Hibernate .

5 голосов
/ 01 июля 2009

Этот шаблон очень распространен в слоях данных на основе Hibernate. Как это работает внутри, во многом зависит от того, какая стратегия наследования используется.

При использовании таблицы для каждого класса или таблицы для наследования подкласса будет создана таблица для каждого подкласса / класса. Например, в вашем случае у вас будет таблица Fruit и две таблицы Apple и Orange с ссылками на внешние ключи между Fruit и Apple / Orange. При запросе одного фрукта (будь то яблоко или апельсин) по идентификатору Hibernate присоединяется к таблице Fruit вместе с таблицей Apple и Orange. Каждая строка будет преобразована в Apple или Orange в зависимости от того, из какой таблицы были получены поля.

Другая возможность - использовать дискриминаторы. Будет использоваться одна таблица Fruit, которая будет содержать поле дискриминатора (например, fruit_type, принимающее значения apple и orange). В зависимости от значения этого поля Hibernate определит, является ли соответствующий объект Apple или Orange.

В вашем случае, в случае активной загрузки, когда Hibernate загружает объект Note, он охотно получает соответствующий Fruit и заполняет поле Fruit экземпляром Apple или Orange соответственно.

В случае ленивого извлечения поле фруктов будет прокси-сервером, реализующим интерфейс Fruit. Пока фактическое поле фруктов не загружено, его тип не определен.

Надеюсь, это ответит на некоторые ваши вопросы.

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