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

JPA Inheritance требует идентификатора в подклассе

У меня проблема с моей моделью домена jpa. Я просто пытаюсь поиграть с простым наследованием, для которого я использую простой базовый класс Person и подкласс Customer. Согласно официальной документации (как JPA, так и EclipseLink), мне нужен только ID-атрибут/столбец в базовом классе. Но когда я запускаю свои тесты, я всегда получаю сообщение об ошибке, указывающее, что у клиента нет @Id?

Сначала я думал, что проблема заключается в видимости атрибута id, потому что он был закрыт первым. Но даже после того, как я изменил его на защищенный (поэтому подкласс имеет прямой доступ), он не работает.

Person

@Entity @Table(name="Persons")
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "TYPE")
public class Person {

    @Id
    @GeneratedValue
    protected int id;
    @Column(nullable = false)
    protected String firstName;
    @Column(nullable = false)
    protected String lastName;

Клиент:

@Entity @Table(name = "Customers")
@DiscriminatorValue("C")
public class Customer extends Person {

    //no id needed here

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

4b9b3361

Ответ 1

Я решил это сам, создав MappedSuperclass

@MappedSuperclass
public abstract class EntityBase{
   @Id
   @GeneratedValue
   private int id;

   ...setter/getter
}

Все объекты наследуются от этого класса. Я все еще задаюсь вопросом, почему в учебниках это не упоминается, но, возможно, это улучшает реализацию JPA 2.

Ответ 2

У меня была точно такая же проблема. Для подкласса я получал:

Entity class [...] has no primary key specified. It should define either an @Id, @EmbeddedId or an @IdClass.

В моем случае оказалось, что я забыл добавить свой корневой класс в persistence.xml.

Убедитесь, что у вас есть как Человек, так и Клиент, определенные в:

<persistence>
  <persistence-unit>
    ...
    <class>package.Person</class>
    <class>package.Customer</class>
    ...
  </persistence-unit>
</persistence>

Ответ 3

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

Я точно не знаю, почему, но когда у меня только один унаследованный класс, у меня не было проблем. Однако, как только я добавил второй и третий, я получил ту же ошибку. Когда я указал аннотацию @Id в дочерней таблице, она снова начала работать.

Мой макет был прост, контактная информация для компаний, агентов и клиентов.

Родительская таблица:

...
@Entity
@Inheritance(strategy= InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="USER_TYPE", length=10, discriminatorType= DiscriminatorType.STRING)
@Table(name="CONTACTS")
public abstract class AbstractContact implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    protected Long id;
    @Column (length=10, nullable=false)
    protected String mapType;
    @Column (length=120, nullable=false)
    protected String mapValue;
...

Контакты агента

@Entity
@DiscriminatorValue("Agent")
public class AgentContact extends AbstractContact implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    protected Long id;
    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="USER_ID")
    protected Agents agent;
}

Контакт компании:

@Entity
@DiscriminatorValue("Company")
public class CompanyContact extends AbstractContact implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    protected Long id;
    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="USER_ID")
    protected Companies company;

}

Клиентские контакты:

@Entity
@DiscriminatorValue("Client")
public class ClientContact extends AbstractContact implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    protected Long id;
    //Client table not built yet so... no mapping
}

Таблица клиентов еще не построена, поэтому нет информации о сопоставлении, но вы получаете точку.

Я хотел поделиться описанием MySQL, но командная строка Windows слишком бесполезна для вырезания/копирования/вставки! По существу, его: ID (int pri) USER_TYPE (VARCHAR (10)) USER_ID (INT) MAPTYPE (VARCHAR (10)) MAPVALUE (VARCHAR (120))

Мне еще нужно настроить все тесты, но пока это выглядит хорошо (я боюсь, что, если я подожду до тех пор, пока не сделаю все тесты, я забуду опубликовать это сообщение)

Ответ 4

JPA знает два разных способа применения наследования:

  • Наследование наследования таблицы
  • Наследование отдельных таблиц

При наследовании одной таблицы вам понадобится столбец дискриминатора, чтобы различать строки в таблице.

С объединенным наследованием таблицы каждый класс получает свою собственную таблицу, поэтому никакой столбец дискриминатора не требуется.

Я думаю, ваша проблема в том, что вы смешали эти две концепции. Итак, либо:

  • определите столбцы дискриминатора и используйте `InheritanceType.SINGLE_TABLE` и не использовать` @Table` в подклассах
  • или используйте `InheritanceType.JOINED`, но не укажите столбец дискриминатора и значения!

Ответ 5

При использовании Glassfish/EclipseLink может возникнуть другая причина: EclipseLink < 2.6.0 имеет неприятную ошибку, вызывая классы с лямбдой выражения в ней должны игнорироваться. Это может привести к запутывающим ошибкам, например, упомянутым здесь, или другим подобным ошибкам (например, EclipseLink может сказать вам, что класс с аннотацией @Entity не является сущностью).

Glassfish 4.1 включает EclipseLink 2.5.x, поэтому эта ошибка (и многие другие) укусит вас, если вы используете Glassfish. Я использовал эту версию вместо 4.1.1 из-за другой ошибки, которая сделала невозможным использование проверки в веб-службах REST. Оставайтесь как можно дальше от Glassfish, если вы хотите сохранить свое здоровье.

Ответ 6

Вы можете получить этот тип ошибки, если не создаете схему базы данных, основанную на ваших объектах. Если это так:

1st - ваш суперкласс всегда должен иметь @Id

2nd. В вашем подклассе должен быть столбец, который идентифицирует расширенный класс (суперкласс @Id)

3rd - Простейшее решение для представленного выше случая добавило бы идентификатор столбца в таблицу подкласса с соответствующим ограничением внешнего ключа.

Надеюсь, это поможет кому-то! Thumbs up!