1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

JPA で ID をラップした専用クラスをマッピングする

Last updated at Posted at 2016-03-25

完全なソースは こちら

追記

Wildfly (Hibernate) だと persist() の後に生成された ID がエンティティにセットされませんでした。
実装依存かもしれません。。。

環境

AP サーバ

Payara Micro 4.1.1.161.1
(JPA 実装:EclipseLink)

DB

Derby (Payara に組み込まれているやつ)

実装

Sample.java
package sample.domain;

import java.util.Objects;

import javax.persistence.Embedded;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.NamedQuery;
import javax.persistence.Table;

@Entity
@Table(name="SAMPLE_TABLE")
@NamedQuery(name="Sample.findAll", query="SELECT sample FROM Sample sample ORDER BY sample.id ASC")
public class Sample {
    
    @EmbeddedId
    private final SampleId id = new SampleId();
    @Embedded
    private SampleValue value;
    
    public void setValue(SampleValue value) {
        this.value = value;
    }

    @Override
    public String toString() {
        return "Sample [id=" + id + ", value=" + value + "]";
    }

    @Override
    public int hashCode() {
        省略
    }
    
    @Override
    public boolean equals(Object obj) {
        省略
    }
}
SampleId.java
package sample.domain;

import java.util.Objects;

import javax.persistence.Embeddable;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;

@Embeddable
public class SampleId {
    
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private final Integer id;

    public SampleId(int id) {
        this.id = id;
    }
    
    SampleId() {
        this.id = null;
    }
    
    @Override
    public String toString() {
        return "SampleId [id=" + id + "]";
    }

    @Override
    public boolean equals(Object obj) {
        省略
    }
    
    @Override
    public int hashCode() {
        省略
    }
}
HelloResource.java
package sample.web;

import java.util.stream.Collectors;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;

import sample.domain.Sample;
import sample.domain.SampleValue;

@Stateless
@Path("hello")
public class HelloResource {
    @PersistenceContext(unitName="SampleUnit")
    private EntityManager em;
    
    @GET
    public String hello(@QueryParam("value") String value) {
        Sample sample = new Sample();
        sample.setValue(new SampleValue(value));
        
        System.out.println("[before persist]" + sample);
        
        this.em.persist(sample);
        
        System.out.println("[after persist]" + sample);
        
        this.em.flush();
        
        System.out.println("[after flush]" + sample);
        
        
        TypedQuery<Sample> query = this.em.createNamedQuery("Sample.findAll", Sample.class);
        return query.getResultList().stream().map(Sample::toString).collect(Collectors.joining("\n"));
    }
}

動作確認

curlで検証
$ curl http://localhost:8080/jpa-sample/api/hello?value=foo
Sample [id=SampleId [id=1], value=SampleValue [value=foo]]
サーバー側出力
[before persist]Sample [id=SampleId [id=null], value=SampleValue [value=foo]]
[after persist]Sample [id=SampleId [id=null], value=SampleValue [value=foo]]
[after flush]Sample [id=SampleId [id=1], value=SampleValue [value=foo]]
  • id が自動採番されてデータベースに保存されている。
  • flush したら、 SampleId にも採番された ID がちゃんと設定されている(final でも構わずに!)。

説明

Sample.java
import javax.persistence.EmbeddedId;

省略

public class Sample {
    
    @EmbeddedId
    private final SampleId id = new SampleId();
  • エンティティのキーとなるフィールドは @EmbeddedId でアノテートする。
  • キーのフィールド(id)には、デフォルトで ID クラス(SampleId)のインスタンスを設定しておく。
    • idnull にしていると persist() したときに落ちる。
    • SampleId オブジェクトが持つ実際の ID 値は null になるようにしておく。
SampleId.java
import javax.persistence.Embeddable;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;

@Embeddable
public class SampleId {
    
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private final Integer id;

    public SampleId(int id) {
        this.id = id;
    }
    
    SampleId() {
        this.id = null;
    }
  • ID となるクラスは @Embeddable でアノテートする。
  • ID の値が設定されるフィールドに @GeneratedValue などのアノテートを設定する。
    • カラム名が実際と異なるなら、このクラスのフィールドを @Column でアノテートする。
  • デフォルトコンストラクタで new した場合は idnull になるようにしておく。

final なのに値が書き換わっているあたり黒魔術感がハンパないけど、とりあえず動いた。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?