How to specify a Primary Key on @ElementCollection
Asked Answered
S

4

12

So, there is that behavior with innodb that can cause problem if some tables lack of primary key.

So with Hibernate, I am looking for a key to specifies a primary key on a @ElementCollection table with a Set as the underling data structure.

I found a way to have a primary key with a map, but it is kind of weird because I do not need a map.

I also found an answer related to @Embeddable, but I do not need that kind of complexities. I am using a Set or Set as the data structure in my entities.

Any idea how to achieve that?

Shu answered 5/5, 2015 at 12:56 Comment(2)
Use a @ManyTo*-like relationship: if you have a primary key, then you have a new entity.Palembang
It is kind of annoying to create a new entity only for a set of int.Shu
I
18

If you use a Set and make the element Column be not null, then hibernate will make a primary key with the join column and element column.

Example:

@Column(name = "STRINGS", nullable = false)
@ElementCollection
private Set<String> strings;
Intent answered 20/11, 2015 at 18:14 Comment(2)
Good simple solution. Worked for me.Fluctuate
Not null has to be set using @Column(nullable = false) and no using @NotNull annotation. @Column(nullable = false) is used for indicating database schema details. See @NotNull vs @Column(nullable = false) for more detailsGreenish
S
6

@ElementCollection cannot take a primary key, because an Embeddable types cannot have an identifier.

You can add an @OrderColumn to optimize the generates SQL statements.

If you need a primary key, then you should turn the @ElementCollection into a @OneToMany association.

Supererogation answered 6/5, 2015 at 6:20 Comment(5)
Do you have any reference for that ?Shu
The article I linked in the answer is a good starting point. Then you have to generate the schema manually to create the PK as Hibernate only supports PK on entities.Supererogation
Oops. It is not a concern of performance, but with MySQL replication, so I do not think @OrderColumn will save me. My real question was : do you have a reference for the restriction on hibernate?Shu
I don't have any other reference for this, just what I sent you.Supererogation
What about usage @org.hibernate.annotations.CollectionId in such case?Tovatovar
O
0

Tested on Spring Boot / Data JPA 2.5.2, hibernate-core 5.4.32:

@Entity
@Table(name = "user")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@Data
@NoArgsConstructor
public class User implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ElementCollection(fetch = FetchType.EAGER, targetClass = Role.class)
    @Enumerated(EnumType.STRING)
    @CollectionTable(
        name = "user_role",
        joinColumns = @JoinColumn(name = "user_id")
    )
    @Column(name = "role", nullable = false)
    private Set<Role> roles; // public enum Role {ADMIN,USER}
}

produces MySQL table:

CREATE TABLE `user_role` (
  `user_id` bigint(20) NOT NULL,
  `role` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  PRIMARY KEY (`user_id`,`role`),
  CONSTRAINT `FK_random_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
)
Orthohydrogen answered 21/7, 2021 at 8:24 Comment(0)
R
0

This example is from a book java persistence with spring data and hibernate, dose not work for a Set, but works for java.util.Collection.Collection or List

@org.hibernate.annotations.GenericGenerator(name = "sequence_gen", strategy = "sequence") @org.hibernate.annotations.CollectionId(column = @Column(name = "NAME_ID"), type = @Type( type = "long"), generator = "sequence_gen" ) @CollectionTable(schema = "", name = "NAMES", joinColumns = @JoinColumn(name = "ROOT_ID")) @ElementCollection private List names = new ArrayList<>();

Rodrigo answered 12/10, 2023 at 15:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.