2

I'am struggling to get Hibernate (with MySQL) to generate the primary key for a reference table from a "main table". My problem is that I got a big table with 25 mil rows and now I need to add multiple additional columns and because in the future where will be even more columns to add I choose the way to work with reference tables instead of adding the columns to the main table (the rebuild takes hours... :)

So there is a main table and a reference table. In my conception the primary key of the reference table should be generated from the primary key of the main table. I could first insert an entry into the main table, then select it and use its primary key for the insert into the reference table, but this seems not to be the best way to me. So I would like to use Hiibernate's generators, but I can't figure out how.

Here's the main table:

@Entity 
@Table
public class Task {

    @Id
    @GeneratedValue
    @Column()
    private Integer id;

    // ...

    @OneToOne(mappedBy = "task_ref", orphanRemoval=true, fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    private Stuff stuff;

    // ...
}

And the reference table:

@Entity
@Table
public class Stuff {

    @Id
    @Column(name = "stuff_id")
    @GeneratedValue()
    private Integer stuff_id;

    // ...

    @OneToOne(orphanRemoval=true, fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @PrimaryKeyJoinColumn
    private Task task_ref;

    // ...
}

So.. how can I use a generator to create the primary key for the table Stuff from the primary key of the table Task ?

Any suggestions or other solutions are highly welcome!

Thanks!

Vlad Mihalcea
  • 142,745
  • 71
  • 566
  • 911
Crayl
  • 1,883
  • 7
  • 27
  • 43
  • 1
    As seem from your code, what you are doing is creating a PK for each of the classes right? But from your explanation you want to use to ID (Pk) of one of the classes as part of the ID (PK) of the other class, right? I am not sure what you want to accomplish with the explanation, could you clarify it a little bit? – Angel Villalain Aug 13 '14 at 13:13
  • @AngelVillalain I'am sorry, the code is confusing. I meant that the PK Stuff.stuff_id shall be generated from the corresponding PK of the main table (Task.id), thus they shall be equal that I can make a JOIN on them. – Crayl Aug 13 '14 at 13:19
  • 1
    Is `Stuff` something like a subclass of `Task`? – Angel Villalain Aug 13 '14 at 13:27
  • Also could you add information on how is the schema in case you can't change the schema so I can have a better picture. – Angel Villalain Aug 13 '14 at 16:32

2 Answers2

2

You could use the Task object as your id, see EmbeddedId or IdClass for an example. In case Stuff represents a subclass of the Task entity in your domain model, you should model this entity as such, in which you will have to represent the Stuff entity as a Joined Subclass of the Task entity. In both cases the extra Id in the Stuff entity is not needed anymore.

Angel Villalain
  • 595
  • 4
  • 16
  • ahh I see. Both are separate classes and rewriting isn't an option :/ – Crayl Aug 13 '14 at 13:37
  • 1
    Configuring to use an `EmbeddedId` or `IdClass` won't impact your database schema if you don't eliminate the extra `id` property. And if you don't want to change the class, then `IdClass` is your best choice. See the following [answer](http://stackoverflow.com/a/3588400/213882) for more information. – Angel Villalain Aug 13 '14 at 16:29
2

This is how you should map your bidirectional OneToOne association with a shared primary key:

@Entity 
@Table
public class Task {

    @Id
    @GeneratedValue
    private Integer id;

    // ...

    @OneToOne(mappedBy = "task_ref", orphanRemoval=true, fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    private Stuff stuff;

// ...
}

@Entity
@Table
public class Stuff {

    @Id
    @Column(name = "stuff_id")
    private Integer stuff_id;

    // ...

    @OneToOne(fetch = FetchType.LAZY)        
    @MapsId 
    @JoinColumn(name = "stuff_id") 
    private Task task_ref;

    // ...
}
  1. Only the parent needs to cascade to the Child entity, not the other way around.
  2. The Parent only has an "inverse" side of the association.
  3. The shared primary key is both a primary key and a foreign key in the Child entity
  4. The MapsId annotation allows you to share the primary key for both the @Id and the OneToOne association
Vlad Mihalcea
  • 142,745
  • 71
  • 566
  • 911