我的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
我的想法和资源都用完了。这应该是一个相当简单的问题,但我只是没有看到它。
答案 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知道两种不同的继承方式:
使用单表继承,您需要一个鉴别器列来区分表中的行。
使用连接表继承,每个类都有自己的表,因此不需要鉴别器列。
我认为你的问题是你混合了这两个概念。所以:
答案 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,但是超类也是一个实体
所有具体的类都将映射到同一张表
每个类都有自己的表。连接的字段将由抽象超类的表映射。
您可以在此处阅读有关JPA继承策略的更多信息:
https://www.thoughts-on-java.org/complete-guide-inheritance-strategies-jpa-hibernate/
如果将类结构拆分到不同的项目中,则可能必须在tsistence.xml中声明超类,如tk.luczak在其回答中所述