5

Мы используем однонаправленное наследование таблицы для каждой таблицы в нашем приложении. Это позволяет различным экземплярам одного и того же стека приложений работать с одними и теми же DAO, в то время как их сущности могут немного отличаться, потенциально содержащие информацию, уникальную для этого экземпляра. Абстрактный класс определяет базовую структуру таблицы и расширение определяет дополнительные столбцы, если это необходимо с помощью этого экземпляра:Можно ли удалить столбец дискриминатора в наследовании одиночной таблицы Hibernate?

@Entity 
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) 
@Table(name = "client") 
public abstract class Client extends AbstractPersistable<Long> { 
    // ... 
} 

Приложение A:

@Entity 
public class ClientSimple extends Client { 
    private String name; 
    // getter, setter 
} 

Приложение Б:

@Entity 
public class ClientAdvanced extends Client { 
    private String description; 
    // getter, setter 
} 

Теперь DAO может работать с объектами Client для приложений A и B, но приложение B может определять дополнительную информацию для своего клиентского объекта, который может быть прочитан методом менеджера uniqu е к применению В:

приложения A:

Client client = new ClientSimple(); 
clientDao.save(client); 

Приложение B:

Client client = new ClientAdvanced(); 
clientDao.save(client); 

К сожалению, это означает, что есть столбец DTYPE в каждой таблице (или любое другое имя, которое я мог бы выбрать) , Есть ли способ избавиться от этого? Нам это не нужно, и он использует пространство БД ...

Спасибо!


EDIT

Важно отметить: @MappedSuperclass не будет работать. Мы используем QueryDSL как наш слой абстракции HQL. Для этого требуются автоматически создаваемые классы типа запроса для запроса типа сохранения. Однако они будут генерироваться только правильно, если абстрактный класс аннотируется @Entity.

Это neccessairy потому что мы хотим, чтобы запрос от абстрактного класса Client в то время как на самом деле запрашивая ClientSimple в приложении А и ClientAdvanced в заявке B:

Так что в любом приложении, это будет работать:

query.where(QClient.client.name.equals("something"); 

и в заявке на патент B это будет работать:

query.where(QClientSimple.client.description.equals("something else"); 

EDIT2 - сводиться

Это, кажется, сводится к следующему: Могу ли я настроить спящий режим во время развертывания, чтобы установить тип дискриминатора для inhertited в сущности фиксированное значение. Итак, идя с моим примером, Client всегда будет ClientSimple в одном приложении и ClientAdvanced в другом, так что мне не нужно хранить эту информацию в базе данных?

Как я уже сказал, каждое приложение будет экземпляром базового стека приложений. Каждое приложение может определять дополнительные столбцы для своей локальной базы данных, но ВСЕ объекты будут одного типа для этого экземпляра, поэтому мы гарантируем, что дискриминатор всегда будет тем же самым, что делает его избыточным в базе данных и прецедентом для конфигурации спящего режима.

+0

Какая версия Querydsl вы используете? –

+0

Мы используем QueryDSL 2.2.3, но можем обновлять, если новые версии поддерживают сопоставленные суперклассы в качестве целей запроса: например: @MappedSuperclass @Table public abstract class Client ... '+' @Entity public class ClientSimple extends Client' == > генерировать типы запросов ... ==> query: 'QClient.client.name' – Pete

+1

Это не поддерживается напрямую, но вы можете добавить к нему билет на GitHub. Это легко реализовать. –

ответ

1

Если вам не нужно использовать как ClientSimple и ClientAdvanced в одном приложении вы можете объявить Client в @MappedSuperclass, а не @Entity.

+0

К сожалению, это невозможно. Мы используем запрос DSL как наш уровень абстракции HQL. Для этого требуется, чтобы абстрактные классы были аннотированы @Entity, чтобы запрос можно было выполнить против абстрактного класса, в то же время запрашивая расширение. Я отредактирую свое сообщение, чтобы отразить это ограничение. – Pete

1

В Hibernate для одиночной таблицы в иерархии классов всегда требуется столбец дискриминатора, чтобы различать сущности, поскольку все классы в одной иерархии хранятся в одной таблице. Пример: Hibernate Single Table per Class Hierarchy.

Но вы можете рассмотреть различные схемы иерархии, как показано ниже:

Hibernate Single Table per Subclass

Преимущества

  • Используя эту иерархию, не требует сложных изменений в базе данных схема при изменении одного родительского класса.
  • Хорошо работает с неглубокой иерархией.

Недостатки

  • По мере роста иерархии, это может привести к снижению производительности.
  • Также увеличивается количество объединений, необходимых для построения подкласса.

Hibernate Single Table per Concrete class

Преимущества

  • Это самый простой способ отображения наследования для реализации.

Недостатков

  • Thats данные принадлежит родительский класс разбросан по ряду таблиц подкласса, который представляет конкретные классы.
  • В большинстве случаев эта иерархия не рекомендуется.
  • Изменения в родительском классе отражается в большом количестве таблиц
  • Запрос выдержано с точки зрения родительского класса, скорее всего, вызовет большое число избранных операций

Я хотел бы предложить вам иметь посмотрите схему «Единая таблица на подкласс».Хотя я не уверен в вашем конкретном требовании. Но это может помочь.

+0

Вы абсолютно уверены, что нет никакого способа написать какой-нибудь пользовательский десериализатор? Я не специалист по спячке, но я готов поспорить, если мы посмотрим, как спящий режим преобразует ResultSet в объект, есть способ настроить его так, как хочет Пит. –

+0

Спасибо за ссылки viralpatel, хорошо прочитал, но, к сожалению, это действительно не помогает. Может быть, это невозможно сделать только с помощью аннотаций, например, подсказки mograbi парня ...?! – Pete

+0

Привет, Гай, ну, конечно, вы можете переопределить многие стандартные функции открытых фреймворков, таких как Hibernate. Но проблема с этим (таблица на иерархию) заключается в том, что ваши данные хранятся в одной таблице. И должен быть столбец для определения того, какая строка данных принадлежит классу в иерархии. –

7

Я знаю, это очень старый вопрос, но я столкнулся с этой проблемой недавно, и это может оказаться полезным для кого-то.

Это можно сделать, используя аннотацию Hibernate's @DiscriminatorFormula. Нижеследующее описание основано на книге Java Persistence with Hibernate, раздел 5.1.3; соответствующая часть начинается на странице последнего абзац на странице 202.

С @DiscriminatorFormula вы можете предоставить в SQL заявление, определяющее значение discriminator при выборке соответствующих строк из базы данных. В вашем случае это должна быть простая строка, которая оценивает какое-то произвольно выбранное значение. Для этого вам необходимо определить имя, которое будет использоваться для вашего объекта Client. Предположим, что вы выбрали «GenericClient» как имя entity. Это имя, которое должно появиться в аннотации @Entity как значение атрибута name. Итак, полный пример, в вашем случае будет выглядеть следующим образом.

@Entity 
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) 
@Table(name = "client") 
@DiscriminatorFormula("'GenericClient'") // *1* 
public abstract class Client extends AbstractPersistable<Long> { 
    // ... 
} 

// Application A 
@Entity 
@DiscriminatorValue("GenericClient") // *2* 
public class SimpleClient extends Client { 
    // ... 
} 


// Application B 
@Entity 
@DiscriminatorValue("GenericClient") // *3* 
public class AdvancedClient extends Client { 
    // ... 
} 

Линия, которая обозначается «» является частью SQL сниппета, который всегда будет возвращать «GenericClient» в качестве значения. subclassesClient всегда должен быть аннотирован @DiscriminatorValue("GenericClient"). Это означает, что когда Hibernate выбирает строки из БД, тип объекта, который должен быть сконструирован, всегда будет конкретным подклассом Client.

Если пакет, где подклассы Client проживают, и имя подклассов фиксированы:

В этом случае @DiscriminatorValue("GenericClient") на подклассы не требуется, все, что вам потребуется

@Entity 
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) 
@Table(name = "client") 
@DiscriminatorFormula("'com.example.fixed.path.FixedSubClassName'") 
public abstract class Client extends AbstractPersistable<Long> { 
    // ... 
} 

Подклассам не нужны никакие аннотации. Значение discriminator-value по умолчанию соответствует entity-name, который сам по себе использует полностью квалифицированное имя класса.

Примечание:SQL заявления внутри @DiscriminatorFormula() может быть любым допустимым SQL заявления на целевой сервер БД.

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