JPA继承要求子类中的ID

时间:2009-09-12 16:20:51

标签: inheritance jpa eclipselink

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

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

人:

@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

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

7 个答案:

答案 0 :(得分:31)

我自己通过创建MappedSuperclass

解决了这个问题
@MappedSuperclass
public abstract class EntityBase{
   @Id
   @GeneratedValue
   private int id;

   ...setter/getter
}

所有实体都继承自此类。我仍然想知道为什么这些教程不提这个,但是JPA 2的实现可能会更好。

答案 1 :(得分:9)

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

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>

答案 2 :(得分: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))

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

答案 3 :(得分:3)

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

  • 加入表继承
  • 单表继承

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

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

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

  • 定义鉴别器列并使用`InheritanceType.SINGLE_TABLE`和在子类上使用`@ Table`
  • 或使用`InheritanceType.JOINED`但指定鉴别器列和值!

答案 4 :(得分:0)

使用Glassfish / EclipseLink时可能还有另一个原因导致此错误:EclipseLink&lt; 2.6.0有一个nasty bug导致其中包含lambda表达式的类被忽略。这可能会导致混淆错误(如此处提到的错误)或其他类似错误(例如,EclipseLink可能会告诉您具有@Entity注释的类不是实体)。

Glassfish 4.1包含EclipseLink 2.5.x,因此如果使用Glassfish,这个错误(以及许多其他错误)会让你感到厌烦。由于另一个无法在REST Web服务中使用验证的错误,我使用的是此版本而不是4.1.1。如果你想保持理智,请尽量远离Glassfish。

答案 5 :(得分:0)

如果您未在实体中生成数据库架构,则可能会遇到此类错误。 如果是这样的话:

1st - 您的超类必须始终拥有@Id

2nd - 你的子类必须有一些标识扩展类的列(超类@Id)

第三 - 上面提到的案例的最简单的解决方案是将列id添加到子类表,并使用相应的外键约束。

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

答案 6 :(得分:0)

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

作为公认的答案,您必须在基类中声明继承。您可以通过4种不同的方式来做到这一点:

  • @MappedSuperclass

将每个具体的类映射到表

  • @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)

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

  • @Inheritance(strategy = InheritanceType.SINGLE_TABLE)

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

  • @Inheritance(strategy = InheritanceType.JOINED)

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

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


如果将类结构拆分到不同的项目中,则可能必须在tsistence.xml中声明超类,如tk.luczak在其回答中所述