pXel
pXel

Reputation: 599

Hibernate refactor @Id field to superclass

Having 2 entity classes for two different database tables, Table1.java that has ids manually generated and Table2.java that has sequence generated ids, is it possible to move the id property, the @Id and @Column annotations, and the getters & setters for id to GenericTable superclass and leave @GeneratedValue and @SequenceGenerator inside subclasses that only need them? The solution must be scalable for hundreds of tables of the two types and should not split GenericTable superclass in two classes.

The problem is that @GeneratedValue works only at field / method level so it must be moved to the superclass making all subclasses mandatory to implement a @SequenceGenerator which conflicts with Table1.java characteristics.

@Entity
@Table(name = "TABLE1")
public class Table1 extends GenericTable {

  @Id
  @Column(name = "ID", nullable = false, precision = 22, scale = 0)
  private Long id;

  // other properties 
  // getters & setters for id
  // other getters & setters
}

@Entity
@Table(name = "TABLE2")
public class Table2 extends GenericTable {

  @Id
  @GeneratedValue(strategy = SEQUENCE, generator = "generator")
  @SequenceGenerator(name = "generator", sequenceName = "TABLE2_SEQ", allocationSize = 1)
  @Column(name = "ID", nullable = false, precision = 22, scale = 0)
  private Long id;

  // other properties 
  // getters & setters for id
  // other getters & setters
}

@MappedSuperclass
public abstract class GenericTable {

}

Upvotes: 1

Views: 4159

Answers (1)

Maciej Kowalski
Maciej Kowalski

Reputation: 26572

I dont think its possible to cram those two configuration types in one class.

I did some tests and with two @MappedSuperclass entities you should be able to achieve a solution which meets your reusable / scalable needs:

Basic Id type parent

@MappedSuperclass
public abstract class BasicIdAwareEntity implements Serializable {

    protected Long id;

    @Id
    @Column(name = "ID", nullable = false, precision = 22, scale = 0)
    public Long getId() {
        return id;
    }

Sequence Id variation parent

@MappedSuperclass
public abstract class SequenceIdAwareEntity extends BasicIdAwareEntity {

  @Override
  @Id
  @GeneratedValue(strategy = SEQUENCE, generator = "generator")
  @SequenceGenerator(name = "generator", sequenceName = "TABLE2_SEQ", allocationSize = 1)
  public Long getId() {
     return super.getId();
  }

Concrete Entities

@Entity
@Table(name = "TABLE1")
public class Table1 extends BasicIdAwareEntity {

and

@Entity
@Table(name = "TABLE2")
public class Table2 extends SequenceIdAwareEntity {

Now if you need to refactor this mapping at some point in the future, for example you need to change the precision of the id column, then you simply make the change in the BasicIdAwareEntity class. The same goes for the type change, which with the help of good IDE should also change the subclasses.

The only annotation that you need to put in all of the abstract classes is the @Id.

If you need to have a different generator for a certain table in the future, then you simply create another subclass of the BasicIdAwareEntity.

Upvotes: 2

Related Questions