Переопределение @Id, определенного в @MappedSuperclass с помощью JPA

У меня есть класс AbstractEntity, который расширяется всеми объектами в моем приложении и в основном действует как поставщик идентификаторов.

@MappedSuperclass
public class AbstractEntity implements DomainEntity {

    private static final long serialVersionUID = 1L;

    /** This object's id */
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    protected long id;

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name="creation_date", nullable = false, updatable=false)
    private Date creationDate = new Date();

    /**
     * @return the id
     */
    public long getId() {
        return this.id;
    }

    /**
     * @param id the id to set
     */
    public void setId(long id) {
        this.id = id;
    }
}

Теперь у меня есть случай, когда мне нужно определить отдельный идентификатор для пары моих классов Entity, поскольку они должны иметь собственный генератор последовательности. Как этого добиться?

@Entity
@Table(name = "sample_entity")
public class ChildEntity extends AbstractChangeableEntity {

    @Column(name = "batch_priority")
    private int priority;

    public int getPriority() {
        return priority;
    }

    public void setPriority(int priority) {
        this.priority = priority;
    }

}

person Sushant    schedule 29.04.2015    source источник
comment
Одним из вариантов может быть переопределение имени генератора в подклассе, который необходимо настроить, но это будет означать, что вы используете один и тот же тип генератора (генератор последовательности) для всех сущностей. Прочтите эту публикацию для получения дополнительной информации. Было бы идеально, если бы вы/мы могли переопределить весь генератор в подклассе, но я не думаю, что это может работать в настоящее время.   -  person Predrag Maric    schedule 29.04.2015


Ответы (3)


Вы не можете этого сделать, как показано на этот пример GitHub.

Как только вы определите @Id в базовом классе, вы не сможете переопределить его в подклассе, а это означает, что лучше оставить ответственность @Id каждому отдельному конкретному классу.

person Vlad Mihalcea    schedule 29.04.2015

Разделите свой базовый класс.

Определяет все общие поля, кроме ID:

@MappedSuperclass
public  abstract class AbstractEntityNoId implements DomainEntity {
 private static final long serialVersionUID = 1L;

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name="creation_date", nullable = false, updatable=false)
    private Date creationDate = new Date();
}

Расширяется выше с генератором идентификатора по умолчанию:

@MappedSuperclass
public abstract class AbstractEntity extends AbstractEntityNoId {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    protected Long id;

    public Long getId(){
       return id;
    }
}

Классы, требующие создания пользовательского идентификатора, расширяют первый, а другие — второй.

С учетом вышеизложенного не потребуется изменять существующий код, кроме объектов, требующих создания пользовательского идентификатора.

person Alan Hay    schedule 29.04.2015
comment
Но я хочу сохранить иерархию, все, что я хочу, это как-то скрыть идентификатор, предоставленный базовым классом. - person Sushant; 29.04.2015
comment
Как было указано, вы не можете. С учетом вышеизложенного вам не нужно изменять какой-либо существующий код, кроме суперкласса тех сущностей, для которых требуется создание пользовательского идентификатора. Все по-прежнему является экземпляром DomainEntity. - person Alan Hay; 29.04.2015

Одним из решений, которое в некоторых случаях неосуществимо, является использование аннотаций в методах get вместо полей. Это даст вам больше гибкости, особенно для переопределения всего, что вы хотите.

В коде:

@MappedSuperclass
public class AbstractEntity implements DomainEntity {

    private static final long serialVersionUID = 1L;

    protected long id;

    private Date creationDate = new Date();

    /**
     * @return the id
     */
    /** This object's id */
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    public long getId() {
        return this.id;
    }

    /**
     * @param id the id to set
     */
    public void setId(long id) {
        this.id = id;
    }

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name="creation_date", nullable = false, updatable=false)
    public Date getCreationDate () {
        return this.creationDate ;
    }
}

И ваш подкласс:

@Entity
@Table(name = "sample_entity")
public class ChildEntity extends AbstractChangeableEntity {


private int priority;

@Override
@Id
@GeneratedValue(strategy = GenerationType.ANOTHER_STRATEGY)
public long getId() {
    return this.id;
}

@Column(name = "batch_priority")
public int getPriority() {
        return priority;
    }
public void setPriority(int priority) {
        this.priority = priority;
    }

}

person Jad B.    schedule 06.08.2018