【问题标题】:JPA Inheritance demands ID in subclassJPA 继承要求子类中的 ID
【发布时间】:2010-11-27 18:43:17
【问题描述】:

我的 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

我的想法和资源已经用完了。这应该是一个比较简单的问题,但我就是没看到。

【问题讨论】:

  • 我也有类似的问题。我相信它是 Eclipse 绑定的。我的 JBoss 开发人员工具抱怨派生实体上缺少 @Id,但 Maven 编译它而没有抱怨。

标签: inheritance jpa eclipselink


【解决方案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 中添加我的根类。

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

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

【讨论】:

    【解决方案3】:

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

    • 加入的表继承
    • 单表继承

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

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

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

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

    【讨论】:

    【解决方案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
    }
    

    clients 表尚未构建,因此没有映射信息,但您明白了。

    我想分享 MySQL 的描述,但 Windows 命令提示符太不值得剪切/复制/粘贴!本质上,它的: ID (int pri) USER_TYPE (VARCHAR(10)) USER_ID (INT) MAPTYPE (VARCHAR(10)) MAPVALUE (VARCHAR(120))

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

    【讨论】:

      【解决方案5】:

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

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

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

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

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

      【讨论】:

        【解决方案6】:

        我看到了一些可能有帮助的答案,但不是一个完整的答案,我会尽力提供一个。

        正如接受的答案所述,您必须在基类中声明继承。有 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/


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

        【讨论】:

          【解决方案7】:

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

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-01-25
            • 1970-01-01
            相关资源
            最近更新 更多