38

I am mapping my classes with the tables of my database, but when running a test, I get the following error:

Caused by: org.hibernate.AnnotationException: A Foreign key refering com.modulos.pvs.acceso.datos.entity.Provincia from com.modulos.pvs.acceso.datos.entity.Ciudad has the wrong number of column. should be 2
    at org.hibernate.cfg.annotations.TableBinder.bindFk(TableBinder.java:429)
    at org.hibernate.cfg.ToOneFkSecondPass.doSecondPass(ToOneFkSecondPass.java:115)
    at org.hibernate.cfg.Configuration.processEndOfQueue(Configuration.java:1550)
    at org.hibernate.cfg.Configuration.processFkSecondPassInOrder(Configuration.java:1473)
    at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1389)
    at org.hibernate.cfg.Configuration.buildMappings(Configuration.java:1345)
    at org.springframework.orm.hibernate3.LocalSessionFactoryBean.buildSessionFactory(LocalSessionFactoryBean.java:717)
    at org.springframework.orm.hibernate3.AbstractSessionFactoryBean.afterPropertiesSet(AbstractSessionFactoryBean.java:211)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1541)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1479)
    ... 40 more

these are my classes:

//    PROVINCIA TABLE
    @Entity
    @Table(name="provincia")
    @NamedQuery(name = "Provincia.findAll", query = "SELECT p FROM Provincia p")
    public class Provincia implements Serializable {

        private static final long serialVersionUID = 1L;

        @EmbeddedId
        private ProvinciaPK id;

        private String nombreProvincia;

        // bi-directional many-to-one association to Region
        @ManyToOne(fetch=FetchType.LAZY)
        @JoinColumn(name = "codRegion")
        private Region region;

        //bi-directional many-to-one association to Ciudad
        @OneToMany(mappedBy="provincia", fetch=FetchType.LAZY)
        private List<Ciudad> ciudad;

    //GETTER AND SETTER

//TABLE CIUDAD
/**
 * The persistent class for the city database table.
 * 
 */
@Entity
@Table(name="ciudad")
@NamedQuery(name = "Ciudad.findAll", query = "SELECT c FROM Ciudad c")
public class Ciudad implements Serializable {
    private static final long serialVersionUID = 1L;

    @EmbeddedId
    private CiudadPK id;

    private String nombreCiudad;

    // bi-directional many-to-one association to Provincia
    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name = "codProvincia", insertable = false, updatable = false)
    private Provincia provincia;

    //bi-directional many-to-one association to Direcciones
    @OneToMany(mappedBy="ciudad", fetch=FetchType.LAZY)
    private List<Direcciones> direcciones;

//  GETTER AND SETTER

both have primary keys are embedded into classes.

//PROVINCIA PK
/**
 * The primary key class for the provincia database table.
 * 
 */
@Embeddable
public class ProvinciaPK implements Serializable {
    //default serial version id, required for serializable classes.
    private static final long serialVersionUID = 1L;

    private String codProvincia;

    private String codRegion;

    public ProvinciaPK() {
    }
    /getter and setter

//ciudad pk
/**
 * The primary key class for the region database table.
 * 
 */
@Embeddable
public class CiudadPK implements Serializable {
    //default serial version id, required for serializable classes.
    private static final long serialVersionUID = 1L;

    private String codCiudad;

    private String codProvincia;

    public CiudadPK() {
    }
//GETTER AND SETTER

and this is my relational model database

enter image description here

anyone have any idea? of that does not work?

EDIT 30/11/2014 - RETURN TO LIST EMPTY ASSOCIATION this is my JUnit test

Region region = new Region();
            region.setId(new RegionPK("RM","CHL"));

            region.setProvincias(regionDAO.getProvinciaRegion(region));

            System.out.println(region.getProvincias());

This is the method that returns me the association of provincias

@Transactional(readOnly=true)
@Override
public List<Provincia> getProvinciaRegion(Region region) {
    region = getRegionById(region);
    Hibernate.initialize(region.getProvincias());
    return region.getProvincias();
}

and this I have in the database

enter image description here

enter image description here

Elias Vargas
  • 1,126
  • 1
  • 18
  • 32

2 Answers2

64

Your class CiudadPK has two columns in it. You're only using @JoinColumn which is limited to a single column. You need to use @JoinColumns and list out both columns in the FK, e.g.

// bi-directional many-to-one association to Provincia
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumns({
  @JoinColumn(name = "codProvincia", insertable = false, updatable = false),
  @JoinColumn(name = "codRegion", insertable = false, updatable = false)
})
private Provincia provincia;

You'll likely have the other issue w/ Ciudad as well, please follow the pattern here to correct that one.

John Ament
  • 11,595
  • 1
  • 36
  • 45
  • Thanks, it worked !, but I have a doubt, because I requires two foreign keys if my table has only one? It is something I have not understood – Elias Vargas Nov 30 '14 at 17:17
  • You're getting a composite primary key because you're using an `@EmbeddedId` in your code. Was this not your intention? – John Ament Nov 30 '14 at 22:21
  • if it was, had confused me, but you enlighten me and I understood. otherwise, because now I try to return the list REGION asociasones in class, but I returns an empty list, you know why is that?. I edited the post with information about this – Elias Vargas Nov 30 '14 at 22:34
  • I have no idea what `Hibernate.initialize` is, is that custom code of yours? Best bet is to start a new question explaining what you're trying to do. Also compare to your domain model - you're missing codCiudad – John Ament Nov 30 '14 at 23:34
  • It works, but when i save a new entity Ciudad, i got a "duplicate key value violates unique constraint" for Provincia", why? – pierre Feb 13 '19 at 21:58
  • Thanks! You saved me time! – RoutesMaps.com Aug 04 '21 at 16:56
  • I got here because of this issue but I already used JoinColumns , though it is a OneToOne. Could that be the cause? – chitgoks Oct 26 '22 at 09:43
10

As of Java 8 (introducing @Repeatable), the wrapper annotation @JoinColumns is no longer required .

So, you can simply do this:

// bi-directional many-to-one association to Provincia
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name = "codProvincia", insertable = false, updatable = false)
@JoinColumn(name = "codRegion", insertable = false, updatable = false)
private Provincia provincia;

References:

Java 8's new Type Annotations

Repeating Annotations

Stephan
  • 41,764
  • 65
  • 238
  • 329
Sumit
  • 2,189
  • 7
  • 32
  • 50