Search code examples
hibernatejpahibernate-mapping

Why am I obtaining this "Repeated column in mapping for entity" into an Hibernate entity? What is the best way to handle this situation?


I am not so into Hibernate and I have the following problem\doubt.

I have this situation:

1) I have this Room entity class that represent a room of an accomodation:

@Entity
@Table(name = "room")
public class Room implements Serializable {

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


    @ManyToOne
    @JoinColumn(name = "id_accomodation_fk", nullable = false)
    private Accomodation accomodation;

    @ManyToOne
    @JoinColumn(name = "id_room_tipology_fk", nullable = false)
    private RoomTipology roomTipology;

    @OneToMany(mappedBy = "room")
    private List<RoomMedia> roomMediaList;

    @Column(name = "room_number")
    private String number;

    @Column(name = "room_name")
    private String name;

    @Column(name = "room_description")
    private String description;

    @Column(name = "is_enabled")
    private Boolean isEnabled;

    ........................................................................
    ........................................................................
    GETTER AND SETTER METHODS
    ........................................................................
    ........................................................................
}

2) Then I have this RoomMedia entity class that represent a photo related to a specific Room entity:

@Entity
@Table(name = "room_media")
public class RoomMedia {

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

    @Column(name = "id_room")
    private Long idRoom;

    @ManyToOne
    @JoinColumn(name = "id_room", nullable = false)     // da rinominare anche sul DB in room_fk
    private Room room;

    @Lob
    @Column(name = "media")
    private byte[] media;

    private String description;

    ........................................................................
    ........................................................................
    GETTER AND SETTER METHODS
    ........................................................................
    ........................................................................

}

As you can see in the previous code these 2 entity classes are linked togheter in this way:

A Room instance represent a specific room and contains the list of its photos, in this way:

@OneToMany(mappedBy = "room")
private List<RoomMedia> roomMediaList;

that means that a single room is linked to many RoomMedia instances. The mappedBy = "room" means that to do the link between Room and RoomMedia use the room field of the RoomMedia entity (that represent the specific room of a RoomMedia instance).

Then in the RoomMedia entity class I have this link:

@ManyToOne
@JoinColumn(name = "id_room", nullable = false)    
private Room room;

Where means that many RoomMedia instances are related to a single Room intsance. The Join operation is done using the id_room field on the room_media table (it is done at table level and not a entity level).

Correct if all this reasoning have something wrong.

My problem is that at the application startup I am obtaining this error message:

Caused by: javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.persistenceException(EntityManagerFactoryBuilderImpl.java:1249)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.access$600(EntityManagerFactoryBuilderImpl.java:120)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:860)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:850)
    at org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl.withTccl(ClassLoaderServiceImpl.java:425)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:849)
    at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:60)
    at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:353)
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:373)
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:362)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1642)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1579)
    ... 39 more
Caused by: org.hibernate.MappingException: Repeated column in mapping for entity: com.betrivius.domain.RoomMedia column: id_room (should be mapped with insert="false" update="false")
    at org.hibernate.mapping.PersistentClass.checkColumnDuplication(PersistentClass.java:709)
    at org.hibernate.mapping.PersistentClass.checkPropertyColumnDuplication(PersistentClass.java:731)
    at org.hibernate.mapping.PersistentClass.checkColumnDuplication(PersistentClass.java:753)
    at org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:506)
    at org.hibernate.mapping.RootClass.validate(RootClass.java:270)
    at org.hibernate.cfg.Configuration.validate(Configuration.java:1360)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1851)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:857)
    ... 48 more

Why Hibernate can't handle both? What is the problem? How can I fix it?

I think that maybe it could depend by the fact that in the RoomMedia instance I still have the id_room field that is no longer needed because in this entity I also have put the:

@ManyToOne
@JoinColumn(name = "id_room", nullable = false)    
private Room room;

that itself contains this id.

So I think that removing this field:

@Column(name = "id_room")
private Long idRoom;

I will solve my problem, is it?

But now I could will have another problem: into my DAO I could have some complex query that involves the idRoom. So, for convenience, I wold have both these private Room room; and private Long idRoom; field into my RoomMedia entity class.

How can I mantain both avoiding this issue?


Solution

  • You should definitely remove this column from mapping

    @Column(name = "id_room")
    private Long idRoom;
    

    and Hibernate tells you the same.

    But now I could will have another problem: into my DAO I could have some complex query that involves the idRoom. So, for convenience, I wold have both these private Room room; and private Long idRoom; field into my RoomMedia entity class.

    Correct mapping is

    @ManyToOne
    @JoinColumn(name = "id_room", nullable = false)    
    private Room room;
    

    and it gives you everything you need

    Query examples

    Query query1 = em.createQuery("select rm from RoomMedia rm where rm.room.id = :id");
    
    Query query2 = em.createQuery("select rm from RoomMedia rm join rm.room r where r.id = :id");