简体   繁体   中英

Map part of composite PK to composite FK

My data model consists of items with a history. I'll call a point in time an "instant"; all tables therefore have an "instant_id" that specifies how that item was configured at that instant. The "instant_id" is rolled into a composite primary key for all tables. Imagine the following example:

Table Computer
============
PK int       instant_id    <-- Shared id
PK int       computer_id   <-- Child id
int computer_type_id    <-- Parent id
varchar      foo

Table ComputerType
==================
PK int  instant_id      <--   Shared id
PK int  computer_type_id   <--  Parent id
varchar bar

There is a foreign key in Computer mapping (instant_id, computer_type_id) to the ComputerType primary key.

We use something like

@Embeddable ComputerId {
   @Column(name='instant_id', nullable=false) int instant_id,
   @Column(name='computer_id', nullable=false) int computer_id
}

Then:

Computer {
   @EmbeddedId ComputerId id;

   @MapsId('instant_id')
   @ManyToOne
   @JoinColumns({
       @JoinColumn(name='instant_id',...),
       @JoinColumn(name='computer_type_id',...)
   })
   ComputerType computerType;
}

No matter how I combine MapsId with JoinColumns, I can't seem to get this to work. Any ideas?

I don't see a ManyToOne association. You are not showing us how ComputerType is declared, I am assuming it's an Entity. If that's the case, per table definition you provided, both Computer and ComputerType share a composite primary key: instant_id and computer_type_id .

If that is true and they share the same primary key, you might be better off normalizing those two tables into one table.

I think I understand the issue now. You need to consider the computer_type_id as part of the composite key for Computer table as well. The column computer_type_id by itself is not quite meaningful; in the ComputerType table it is a part of the primary key, the other part being instant_id. So if that's the case, you need to include it as part of the primary key for Computer table as well, because you will never have a case where Computer.instant_id = ComputerType.instant_id AND Computer.computer_type_id <> ComputerType.computer_type_id, for a given related association. (If I understand this case correctly)

If you agree with that, then here is the solution:

@Embeddable
public class ComputerId implements Serializable {
    int computer_id;

    @ManyToOne
    @JoinColumns({@JoinColumn(name = "instant_id", insertable=false, updatable=false), 
        @JoinColumn(name = "computer_type_id", insertable=false, updatable=false) })
    ComputerType computerType;
    // getters and setters
}

@Entity
public class Computer {
    @EmbeddedId
    ComputerId computerId;
    // getters and setters
}

public class ComputerTypeId implements Serializable {
       @Column(name="instant_id", nullable=false) int instant_id;
       @Column(name="computer_type_id", nullable=false) int computer_type_id;
       // getters and setters
}

@Entity
public class ComputerType {
    @EmbeddedId
    ComputerTypeId computerTypeId;
    String bar;
    // getters and setters
}

Finally, you might want to consider Hibernate Envers for Entity versioning.

Hope this helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM