32

我的 jpa 域模型有问题。我只是想尝试简单的继承,为此我使用了一个简单的 Person 基类和一个 Customer 子类。根据官方文档(JPA 和 EclipseLink),我只需要基类中的 ID 属性/列。但是当我运行我的测试时,我总是得到一个错误,告诉我客户没有@Id?

首先,我认为问题在于 id 属性的可见性,因为它首先是私有的。但即使我将其更改为受保护(因此子类可以直接访问)它也无法正常工作。

人:

@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

我的想法和资源已经用完了。这应该是一个相当简单的问题,但我只是没有看到它。

4

7 回答 7

40

我通过创建一个 MappedSuperclass 自己解决了这个问题

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

   ...setter/getter
}

所有实体都继承自这个类。我仍然想知道为什么教程没有提到这一点,但也许 JPA 2 实现会变得更好。

于 2009-09-14T23:40:11.587 回答
9

我有完全相同的问题。对于我得到的子类:

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

就我而言,事实证明我忘记在persistence.xml.

确保您在以下位置定义了 Person 和 Customer:

<persistence>
  <persistence-unit>
    ...
    <class>package.Person</class>
    <class>package.Customer</class>
    ...
  </persistence-unit>
</persistence>
于 2012-09-12T20:05:01.697 回答
4

JPA 知道应用继承的两种不同方式:

  • 连接表继承
  • 单表继承

使用单表继承,您将需要一个鉴别器列来区分表中的行。

通过连接表继承,每个类都有自己的表,因此不需要鉴别器列。

我认为你的问题是你混合了这两个概念。所以要么:

  • 定义鉴别器列并使用`InheritanceType.SINGLE_TABLE`并且不要在子类上使用`@Table`
  • 或使用 `InheritanceType.JOINED` 但不要指定鉴别器列和值!
于 2009-09-12T16:59:26.173 回答
4

我知道这是旧的,但仍然有效。我遇到了同样的问题。但是,@MappedSuperClass 与 Single 继承表不同。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))

我仍然必须设置所有测试,但到目前为止看起来不错(我担心如果我等到完成所有测试后我会忘记发布这个)

于 2011-12-28T04:31:47.053 回答
1

当您不基于实体生成数据库架构时,您可能会收到此类错误。如果是这样的话:

1st - 你的超类必须总是有一个@Id

第二 - 您的子类必须有一些标识扩展类的列(超类@Id)

第 3 - 对于上述情况,最简单的解决方案是将列 id 添加到子类表中,并具有相应的外键约束。

希望这对某人有帮助!竖起大拇指!

于 2016-10-17T00:58:24.763 回答
1

正如我看到的一些可能有帮助的答案,但不是一个完整的答案,我会尝试提供一个。

正如接受的答案所述,您必须在基类中声明继承。有 4 种不同的方法可以做到这一点:

  • @MappedSuperclass

将每个具体类映射到表

  • @Inheritance(策略 = InheritanceType.TABLE_PER_CLASS)

类似于@MappedSuperclass 但超类也是一个实体

  • @Inheritance(策略 = InheritanceType.SINGLE_TABLE)

所有具体类都将由同一张表映射

  • @Inheritance(策略 = InheritanceType.JOINED)

每个班级都有自己的桌子。连接字段将由抽象超类的表映射。

您可以在此处阅读有关 JPA 继承策略的更多信息:
https ://www.thoughts-on-java.org/complete-guide-inheritance-strategies-jpa-hibernate/


如果类结构被拆分为不同的项目,您可能必须在您的 persistence.xml 中声明超类,如 tk.luczak 在他的回答中所述

于 2018-10-22T08:48:05.063 回答
0

使用 Glassfish / EclipseLink 时出现此错误可能还有另一个原因:EclipseLink <2.6.0 有一个令人讨厌的错误,导致其中包含 lambda 表达式的类被忽略。这可能会导致令人困惑的错误,例如此处提到的错误,或其他类似错误(例如,EclipseLink 可能会告诉您带有 @Entity 注释的类不是实体)。

Glassfish 4.1 包括 EclipseLink 2.5.x,所以如果使用 Glassfish,这个错误(以及许多其他错误)会咬你。我使用的是这个版本而不是 4.1.1,因为另一个错误导致无法在 REST Web 服务中使用验证。如果您想保持理智,请尽可能远离 Glassfish。

于 2016-02-25T09:19:25.600 回答