Search code examples
springjpaeclipselink

@JoinColumn must be specified for each join column using the @JoinColumns


I am trying to implement many to many relationship with extra column, but gettig below error. Could somebody explain why below error is occurring anf how to solve?

Internal Exception: Exception [EclipseLink-7220] (Eclipse Persistence Services - 2.4.1.v20121003-ad44345): org.eclipse.persistence.exceptions.ValidationException Exception Description: The @JoinColumns on the annotated element [field extension] from the entity class [class com.polycom.cloudAxis.model.ip.ProfileExtensionMapping] is incomplete. When the source entity class uses a composite primary key, a @JoinColumn must be specified for each join column using the @JoinColumns. Both the name and the referencedColumnName elements must be specified in each such @JoinColumn. at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.createPredeployFailedPersistenceException(EntityManagerSetupImpl.java:1541) at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.predeploy(EntityManagerSetupImpl.java:1532) at org.eclipse.persistence.jpa.PersistenceProvider.createContainerEntityManagerFactory(PersistenceProvider.java:235)

Profile

@Entity
@Table(name = "profile")
public class Profile extends AbstractPersistable<Long> {

private static final long serialVersionUID = 1L;

@Column(name = "instanceType")
private InstanceType instanceType;

@Column(name = "isDefault")
private boolean isDefault;

@Column(name = "profileType")
private ProfileType profileType;

@OneToMany(mappedBy = "profile")
private Set<ProfileExtensionMapping> profileExtensionMappings;

@Id
@Column(name = "profile_id")
private Long profile_id;

}

Extension:

@Table(name = "extension")
@Entity
public class Extension extends AbstractPersistable<Long> {

private static final long serialVersionUID = 1L;

@Lob
@Basic(optional = false)
@Column(name = "json")
private byte[] json;

@Id
@Column(name = "extension_id")
private Long extension_id;

public Long getExtension_id() {
    return extension_id;
}

public void setExtension_id(Long extension_id) {
    this.extension_id = extension_id;
}

@OneToMany(mappedBy = "extension")
private Set<ProfileExtensionMapping> profileExtensionMappings;

}

ProfileExtensionMapping:

@Entity
@Table(name = "profile_extension_mapping")
@IdClass(ProfileExtensionPK.class)
public class ProfileExtensionMapping extends AbstractPersistable<Long> {

private static final long serialVersionUID = 1L;

@Id
@Column(name = "profile_id", insertable = false, updatable = false)
private Long profile_id;

@Id
@Column(name = "extension_id", insertable = false, updatable = false)
private Long extension_id;

@ManyToOne
@JoinColumns({ @JoinColumn(name = "profile_id", referencedColumnName = "profile_id",    nullable = false) })
private Profile profile;

@ManyToOne
@JoinColumns({ @JoinColumn(name = "extension_id", referencedColumnName = "extension_id", nullable = false) })
private Extension extension;

@Column(name = "type")
private ExtensionType extensionType;

@Column(name = "name")
private ExtensionName extensionName;
}

Solution

  • You shouldn't use JoinColumns when you have just one column. Simply use JoinColumn:

    @ManyToOne
    @JoinColumn(name = "profile_id", nullable = false)
    private Profile profile;
    
    @ManyToOne
    @JoinColumn(name = "extension_id", nullable = false)
    private Extension extension;
    

    Now the other problem is that profile_id and extension_id are mapped both as an ID column and as a ManyToOne association. This is possible, but needs additional configuration. You should do like for all the other entities, tough, and use a single column, auto-generated ID, mapped to a single field of type Long. Things will be much simpler, and more efficient.

    Also, consider respecting Java naming conventions and thus naming your field profileId and not profile_id (same for the other fields and the getters/setters, of course).