Подтвердить что ты не робот

Одиночное наследование таблицы WITHOUT Discriminator

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

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

Я пытаюсь сопоставить два класса с одной таблицей, используя JPA с помощью Hibernate. Идея состоит в том, чтобы иметь только небольшое подмножество столбцов в родительском классе и больше/полностью задано в дочернем классе. Наследование НЕТ ТАБЛИЦЫ, только наследование классов. Как это можно сделать?

Выполнение этого не будет работать:

@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, поскольку он используется для сохранения в другом месте.

4b9b3361

Ответ 1

@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
}

Ответ 2

Есть несколько способов, каждый из которых имеет свои собственные оговорки.

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

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

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

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

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

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

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

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

Ответ 3

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

Ответ 4

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

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

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

Ответ 5

Если вы не хотите добавлять автоматический столбец dtype, вам следует определить свой собственный дискриминатор с помощью @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 {
...

Имя Дискриминатора по умолчанию равно имени класса 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)
    )