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
検討すべきアイデアやリソースが不足しています。それはかなり単純な問題であるはずですが、私はそれを見ていません。
MappedSuperclassを作成して自分で解決しました
@MappedSuperclass
public abstract class EntityBase{
@Id
@GeneratedValue
private int id;
...setter/getter
}
すべてのエンティティはこのクラスから継承しています。チュートリアルでこれについて言及されていない理由はまだ疑問ですが、JPA2の実装で改善される可能性があります。
私はまったく同じ問題を抱えていました。私が得ていたサブクラスの場合:
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>
私はこれが古いことを知っていますが、それでも有効です。私は同じ問題に遭遇しました。ただし、@ MappedSuperClassは単一継承テーブルと同じではありません。 MappedSuperClassは、サブクラスごとに個別のテーブルを作成します(私が理解しているように)
正確な理由はわかりませんが、継承されたクラスが1つしかない場合は、問題はありませんでした。ただし、2番目と3番目を追加すると、同じエラーが発生しました。子テーブルで@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))
私はまだすべてのテストをセットアップする必要がありますが、これまでのところそれは良さそうです(すべてのテストを行うまで待つと、これを投稿するのを忘れてしまうのではないかと心配しています)
JPAは、継承を適用する2つの異なる方法を知っています。
単一テーブル継承では、テーブルの行を区別するための識別子列が必要になります。
結合されたテーブル継承では、各クラスが独自のテーブルを取得するため、識別子列は必要ありません。
あなたの問題は、2つの概念を混ぜ合わせたことだと思います。だからどちらか:
役立つかもしれないが完全な答えではないいくつかの答えを見たので、私はそれを提供しようとします。
受け入れられた回答が述べているように、基本クラスで継承を宣言する必要があります。それを行うには4つの異なる方法があります。
各具象クラスをテーブルにマップします
@MappedSuperclassに似ていますが、スーパークラスもエンティティです
すべての具象クラスは同じテーブルによってマップされます
すべてのクラスは独自のテーブルを取得します。結合されたフィールドは、抽象スーパークラスのテーブルによってマップされます。
JPA継承戦略の詳細については、次を参照してください。
https://www.thoughts-on-Java.org/complete-guide-inheritance-strategies-jpa-hibernate/
クラス構造が異なるプロジェクトに分割されている場合、tk.luczakが彼の回答で述べているように、persistence.xmlでスーパークラスを宣言する必要があるかもしれません。
Glassfish/EclipseLinkを使用している場合、このエラーには別の理由がある可能性があります。EclipseLink<2.6.0には 厄介なバグ があり、ラムダ式を含むクラスが無視されます。これにより、ここで説明したような紛らわしいエラーや他の同様のエラーが発生する可能性があります(たとえば、EclipseLinkは、@ Entityアノテーションを持つクラスがエンティティではないことを通知する場合があります)。
Glassfish4.1にはEclipseLink2.5.xが含まれているため、Glassfishを使用している場合、このバグ(および他の多くのバグ)が問題になります。 REST Webサービスで検証を使用できなくなった別のバグのため、4.1.1の代わりにこのバージョンを使用していました。正気を保ちたい場合は、Glassfishからできるだけ離れてください。
エンティティに基づいてデータベーススキーマを生成していない場合、このタイプのエラーが発生する可能性があります。その場合:
1番目-スーパークラスには常に@Idが必要です
2番目-サブクラスには、拡張クラス(スーパークラス@Id)を識別する列が必要です。
3番目-上記のケースの最も簡単な解決策は、対応する外部キー制約を使用して、サブクラステーブルに列IDを追加することです。
これが誰かを助けることを願っています!いいぞ!