2009-06-11 3 views
10

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

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

У меня есть абстрактный класс Фрукты, которые будут подклассифицированы в Apple и Orange. У меня есть класс Note, который представляет примечания или комментарии о яблоках и апельсинах. У Apple или Orange может быть много связанных с ним Notes , но только один 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; 
    } 
} 

Вот класс Примечания реализуется в настоящее время, в котором мы видим, что имеет поле для оба яблока и апельсина. Недостаток или несоответствие в этом дизайне состоит в том, что экземпляр одной заметки будет указывать только на один из Apple или Orange, и оба они оба. Поэтому, если примечание привязано к Apple, оранжевое поле является излишним и неприглядным, а наоборот.

// 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; 
    } 

    ... 
} 

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

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

, после чего фрукты будут либо экземпляром Apple, либо апельсином.

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

+0

У меня есть аналогичная проблема из-за моего кода, работающего над базой данных MySQL. Вы готовы помочь мне с моим родственным вопросом? Вот ссылка: http://stackoverflow.com/questions/25252541/generatedvalue-for-a-java-abstract-superclass-over-mysql – CodeMed

ответ

13

Это абсолютно возможно. Вы можете связать ноты с абстрактным 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; 
    ... 
} 

вуаля!

- Дополнение на основе комментариев: JPA предоставляет несколько стратегий для работы с наследованием. relevant section in the Java EE tutorial должен помочь вам приступить к работе.

В принципе, ваши варианты:

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

Другое редактирование: Заметил, что это спящий режим, а не вопрос JPA. Однако не имеет особого значения, поскольку параметры одинаковы. Вот relevant section in the Hibernate docs.

+0

Временный -1: это не отвечает на вопрос, не так ли? Вы сказали Hibernate об отношениях между Fruit and Note. Как вы рассказываете, как разузнавать Фрукты как Apple, так и Orange? –

+1

@ Джейсон: На ​​самом деле, это так, и очень буквально. Если вы снова прочитаете вопрос, особенно последние абзацы, начиная со второго блока кода, код, который я предоставляю, - это именно то, о чем просит ae6rt. – Henning

+0

-1 удален ... не могли бы вы рассказать о том, как Apple хранится в базе данных иначе, чем Orange? –

4

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

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

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

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

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

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

Смежные вопросы