読者です 読者をやめる 読者になる 読者になる

量産型エンジニアの憂鬱

きっと僕は何物にもなれない。

JPA使ってデータベース初期化するときに同じクラスの@Embeddedが重複してる場合の対応

Java hibernate

早速ですが以下のようなクラスがあったとします。

@Entity
class User {
    @Id
    private Long id;

    private String firstName;

    private String lastName;

    private String firstNameOfRecipient;
    
    private String lastNameOfRecipient;
}

@Embedded@Embeddableを使って分解したいですね。

@Entity
class User {
    @Id
    private Long id;

    @Embedded
    private Name name;

    @Embedded
    private Name recipient;
}

@Embeddable
class Name {
    private String firstName;

    private String lastName;
}

これをSpringBootのspring.jpa.hibernate.ddl-autoを使って生成した場合に以下のようなエラーになりました。

Caused by: org.hibernate.MappingException: Repeated column in mapping for entity: com.duck8823.model.hoge.User column: first_name (should be mapped with insert="false" update="false")
    at org.hibernate.mapping.PersistentClass.checkColumnDuplication(PersistentClass.java:709) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
    at org.hibernate.mapping.PersistentClass.checkPropertyColumnDuplication(PersistentClass.java:731) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
    at org.hibernate.mapping.PersistentClass.checkPropertyColumnDuplication(PersistentClass.java:727) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
    at org.hibernate.mapping.PersistentClass.checkColumnDuplication(PersistentClass.java:753) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
    at org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:506) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
    at org.hibernate.mapping.RootClass.validate(RootClass.java:270) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
    at org.hibernate.cfg.Configuration.validate(Configuration.java:1360) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1851) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:857) ~[hibernate-entitymanager-4.3.11.Final.jar:4.3.11.Final]
    ... 29 common frames omitted

フィールド名でカラムを作成するのですが、下のソースコードの場合Name型のnamerecipientもどちらもfirstNamelastNameカラム名を生成しようとするので競合してしまいます。
これを回避するには、@AttributeOverrides@AttributeOverrideを利用して、こんな感じに書くといいです。

@Entity
class User {
    @Id
    private Long id;

        @Embedded
    private Name name;

    @AttributeOverrides({
        @AttributeOverride(name = "firstName", column = @Column(name = "firstNameOfRecipient")),
        @AttributeOverride(name = "lastName",  column = @Column(name = "lastNameOfRecipient"))
    })
    @Embedded
    private Name recipient;
}

@AttributeOverrideで指定したnameプロパティについて、columnで指定した@Columnでオーバーライドすることができます。