Наследование в одной таблице БЕЗ Дискриминатора - PullRequest
19 голосов
/ 04 июля 2011

Доброе утро, мои дорогие товарищи,

Это начинает раздражать - простая вещь, но часы борьбы, старею ли я ??

Я пытаюсь нанести на картудва класса в одну таблицу с использованием JPA от Hibernate.Идея состоит в том, чтобы иметь только небольшое подмножество столбцов в родительском классе и больший / полный набор в дочернем классе.Нет никакого наследования TABLE, только наследование классов.Как это можно сделать ??

Это не будет работать:

@Entity
@Table(name = "the_table")
class Parent implements Serializable {
}

@Entity
@Table(name = "the_table")
class Child extends Parent implements Serializable {
}

Hibernate предполагает стратегию наследования по умолчанию InheritanceType.SINGLE_TABLE и ищет столбец дискриминатора - по умолчанию DTYPE.Но подождите - нет наследования таблиц, поскольку наличие столбца дискриминатора не имеет смысла.

Я также взглянул на PolymorphismType.EXPLICIT, который не имел никакого значения.Трассировка стека:

Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'apprentice0_.DTYPE' in 'where clause'
   at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
   at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
   at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
   at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
   at com.mysql.jdbc.Util.handleNewInstance(Util.java:411)
   at com.mysql.jdbc.Util.getInstance(Util.java:386)
   at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1052)
   at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3597)
   at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3529)
   at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1990)
   at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2151)
   at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2625)
   at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2119)
   at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:2281)
   at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeQuery(NewProxyPreparedStatement.java:76)
   at org.hibernate.jdbc.AbstractBatcher.getResultSet(AbstractBatcher.java:208)
   at org.hibernate.loader.Loader.getResultSet(Loader.java:1808)
   at org.hibernate.loader.Loader.doQuery(Loader.java:697)
   at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:259)
   at org.hibernate.loader.Loader.loadEntity(Loader.java:1881)

да, еще одна вещь:

@MappedSuperclass и @Embeddable бесполезны, так как их нельзя использовать вместе с @Entity- родительским классом должен быть сам @Entity, поскольку он используется для сохранения в другом месте.

Ответы [ 5 ]

20 голосов
/ 04 июля 2011

@MappedSuperclass - аннотация, которая должна использоваться.Если один и тот же класс является сопоставленным суперклассом и сущностью, то просто разделите его на два класса:

@MappedSuperclass
public class Parent {
    // ...
}

@Entity
public class ParentEntity extends Parent {
    // no code at all here
}

@Entity
public class Child extends Parent {
    // additional fields and methods here
}
8 голосов
/ 28 марта 2015

Существует несколько способов, каждый из которых имеет свои собственные предостережения.

1) Добавьте аннотации следующим образом:

@DiscriminatorFormula("0")
@DiscriminatorValue("0")
class BaseClass{  }

@DiscriminatorValue("00")
class SubClass extends BaseClass{  }

, где значение дискриминатора подклассов должно отличаться от базового класса 'но также оценивать то же значение при передаче в метод Integer.valueOf (String s).

Предупреждение - если вы возвращаете объект из Hibernate базового класса, а затем снова при вызове типа подкласса, который выполучит ошибку с жалобой, что загруженный объект был неправильного класса.Если вы сначала вызовете запрос подкласса, то вызов базового класса вернет подкласс.

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

Предостережение - у вас будет возможность создать одну и ту же строку в виде двух разных объектов, которые не будут синхронизированы и могут привести кк конфликтующим / потерянным обновлениям базы данных.

Вероятно, лучше придерживаться одного типа для сеанса, и это можно было бы обработать без рисков времени выполнения, используя xml-файл сопоставления сущностей, который переопределяет DiscriminatorValue желаемого класса для соответствияпостоянное значение Discriminator'Formula, которое вы можете передать в исходную конфигурацию.

2 голосов
/ 04 июля 2011

Создайте таблицу с ограниченным набором столбцов и сопоставьте второй класс с этим. Определите интерфейс с ограниченным набором столбцов и пусть оба класса реализуют интерфейс. Это, вероятно, дает вам около 95% того, что вам нужно. Если вам нужно, создайте методы для определения равенства между ними, а также возможности преобразования большего класса (с помощью конструктора?) В меньший класс.

1 голос
/ 04 июля 2011

Вы должны выбрать тип наследования для двух сущностей.

То, что вы пытаетесь сделать, не подходит, потому что hibernate не будет знать, какие объекты создавать.

Если вам просто нужно, чтобы у объекта было меньше полей, не отображайте его как сущность - просто предоставьте конструктор, который копирует все поля из другого класса.

0 голосов
/ 15 мая 2019

Если вы не хотите добавлять столбец auto dtype, вам следует определить свой собственный Discriminator с помощью @ DiscriminatorFormula

@Entity
@Table(name = "CS_CUSTOMER")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorFormula("case when id < 3 then 'VIP' else 'Customer' end")
public class Customer extends BaseEntity {
...
@Entity
public class VIP extends Customer {
...

Имя Discriminator по умолчанию равно имени класса Entity, если вы хотите изменить его,использовать

@DiscriminatorValue("VIP")  

Журнал из спящего режима

Hibernate: create sequence hibernate_sequence start with 1 increment by 1
Hibernate: 

    create table cs_customer (
       id bigint not null,
        create_user_id bigint,
        first_name varchar(255),
        last_name varchar(255),
        primary key (id)
    )
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...