Search code examples
jpamany-to-manyunique-indexsurrogate-keycompound-key

JPA - Compound key vs generated id in Many to many table


I am creating a kind of social network and I have users that can follow other users. So I have an entity like:

@Entity
public class FollowedUser{
    @ManyToOne
    private User user;

    @ManyToOne
    private User followedUser;

    //more fields

    ...
}

I cannot have a ManyToMany relationship as I have more fields in my FollowedUser entity. Now, the questions I have are:

  1. Should I use a compound key or a generated id (surrogate key)? I have read the following links (1, 2, 3) about the topic where a surrogate key is suggested, but I don't know if they apply to my concrete case (where my compound key would be composed of two surrogate foreign keys). Also here (4) it says "Composite primary keys typically arise when mapping from legacy databases" so I suppose they are discouraged.
  2. In case I should use a compound key, I don't know if I should use @IdClass (as recommended here 5) or @EmbeddedId (as recommended here 6) or any other option. Although I suppose it doesn't matter.
  3. In case I should use a surrogate key, I don't know how to still make impossible to have the compound candidate key repeated. I have read here (7) about unique indexes but I don't know if it is the correct workaround to that problem.

Solution

  • 1. I recommend using surrogate keys. I find it helpful to separate the database identity of a record from it's business identity. If the two concepts are mixed, it may be cumbersome to model them right and to remodel them later. You reference some good answers, so you are probably aware of the major up- and downsides, no need to reiterate them here. One additional point is that you can rely on the surrogate key like UUID to implement equals and hashCode properly. Implementing those for a composite keys to play nicely with both collections and the db can be tricky.

    As to your use case, a connection between users can be viewed as an entity of it's own and have a autogenerated surrogate PK. You can enforce the uniqueness of the business key attributes in the DB, see pt.3.

    2. AFAIK, deciding between EmbeddedId and IdClass is mostly a matter of taste. I prefer IdClass, since it avoids having to add navigation when querying id attributes:

    ... WHERE a.id.attribute = :att with EmbeddedId vs.

    ... WHERE a.attribute = :att vs. with IdClass

    I do not find the argument you link 6 convincing. Composite keys tend to consist of the most characteristic attributes of the entity. To hide them away in a different class because they happen to be used as the DB key seems awkward to me.

    3. Unique indexes look like a good way to guarantee uniqueness of a combination of attributes. You may want to read this answers, there is a small example.

    If you are not yet working with JPA 2.1, you might want to use unique constraints, as explained here.