Rapidistul
Rapidistul

Reputation: 564

Embedded id and "repeated column in mapping for entity..." exception

I have a problem with JPA and Hibernate and I fail to solve it.

So, it is my applicationContext.xml:

<context:component-scan base-package="com.abt.fiifootballmanager">
    <context:exclude-filter type="annotation"
        expression="org.springframework.stereotype.Controller" />
</context:component-scan>

<jdbc:embedded-database type="HSQL" id="dataSource" />

<bean
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
    id="emf">
    <property name="packagesToScan" value="com.abt.fiifootballmanager.entity" />
    <property name="dataSource" ref="dataSource" />
    <property name="jpaProperties">
        <props>
            <prop key="hibernate.show_sql">true</prop>
            <prop key="hibernate.hbm2ddl.auto">create</prop>
        </props>
    </property>
    <property name="persistenceProvider">
        <bean class="org.hibernate.jpa.HibernatePersistenceProvider" />
    </property>
</bean>

<tx:annotation-driven transaction-manager="transactionManager"/>

<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">
    <property name="dataSource" value="dataSource"/>
</bean>

This is my Performance entity:

 package com.abt.fiifootballmanager.entity;

import java.io.Serializable;
import javax.persistence.*;
import java.math.BigDecimal;
import java.util.List;

@Entity
@Table(name="PERFORMANCES")
@NamedQuery(name="Performance.findAll", query="SELECT p FROM Performance p")
public class Performance implements Serializable {
    private static final long serialVersionUID = 1L;

    @EmbeddedId
    private PerformancePK id;

    @Column(name="RED_CARD")
    private BigDecimal redCard;

    @Column(name="YELLOW_CARD")
    private BigDecimal yellowCard;

    @OneToOne(mappedBy="performance")
    private GoalkeepingPerformance goalkeepingPerformance;

    @OneToMany(mappedBy="performance")
    private List<OutfieldPerformance> outfieldPerformances;

    @ManyToOne
    @JoinColumn(name="MATCH_ID")
    private Match match;

    @ManyToOne
    @JoinColumn(name="PLAYER_ID")
    private Player player;
    ...getters & setters }

And this is my embedded id class:

@Embeddable
public class PerformancePK implements Serializable {
    //default serial version id, required for serializable classes.
    private static final long serialVersionUID = 1L;

    @Column(name="MATCH_ID", insertable=false, updatable=false)
    private long matchId;

    @Column(name="PLAYER_ID", insertable=false, updatable=false)
    private long playerId;
    ... //getters and setters

So, these are my classes. But when I want to run my application I get the next exceptions: 1.Error creating bean with name 'emf' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory

2. Repeated column in mapping for entity: com.abt.fiifootballmanager.entity.Performance column: MATCH_ID (should be mapped with insert="false" update="false")

I think that the first exception it's caused by the second. So, why I get "Repeated column in mapping for entity?". It's a good idea to use an embedded id class?.

Upvotes: 11

Views: 23697

Answers (3)

Eugene
Eugene

Reputation: 2701

I encountered the same problem, and solved it by changing @Embeddedable/@EmbeddedId with @IdClass.

Your classes should look like (i omit some info):

@Entity
@Table(name="PERFORMANCES")
@IdClass(PerformancePK.class)
public class Performance implements Serializable {

  @Id
  @Column(name="MATCH_ID")
  private long matchId;

  @Id
  @Column(name="PLAYER_ID")
  private long playerId;

  @ManyToOne
  @JoinColumn(name="MATCH_ID", insertable = false, updatable = false)
  private Match match;

  @ManyToOne
  @JoinColumn(name="PLAYER_ID", insertable = false, updatable = false)
  private Player player;

  ...//getters, setters
}


public class PerformancePK implements Serializable {

    private long matchId;

    private long playerId;

    ... //getters and setters

    // !!! MANDATORY: override hashCode() and equals() here
}

With this construction, your DB structure still the same. More information about @IdClass usage.

Upvotes: 3

David Levesque
David Levesque

Reputation: 22451

It may be possible to do this using @EmbeddedId, but it may be easier to use the @IdClass annotation at the entity level. You can then set the @Id annotation on the @ManyToOne references directly:

@Entity
@Table(name="PERFORMANCES")
@IdClass(PerformancePK.class)
@NamedQuery(name="Performance.findAll", query="SELECT p FROM Performance p")
public class Performance implements Serializable {

    static public class PerformancePK implements Serializable {
        private long match;
        private long player;

        public PerformancePK() {
        }

        public PerformancePK(long match, long player) {
            this.match = match;
            this.player = player;
        }

        // TODO: implements equals() and hashCode()
    }

    @Id
    @ManyToOne
    @JoinColumn(name="MATCH_ID")
    private Match match;

    @Id
    @ManyToOne
    @JoinColumn(name="PLAYER_ID")
    private Player player;

    ...
}

I have defined the PerformancePK class as an inner class because I find it convenient, but it doesn't have to be.

Upvotes: 0

forgivenson
forgivenson

Reputation: 4435

Your two variables match and player in your Performance class are mapped to the same columns as matchId and playerId in the embedded ID. As the error says, they "should be mapped with insert="false" update="false"".

@ManyToOne
@JoinColumn(name="MATCH_ID", insertable = false, updatable = false)
private Match match;

@ManyToOne
@JoinColumn(name="PLAYER_ID", insertable = false, updatable = false)
private Player player;

This essentially makes those fields readonly, so Hibernate knows only to change the MATCH_ID and PLAYER_ID columns if the values in the embedded ID are changed, but not if the values of match or player are changed.

Upvotes: 19

Related Questions