Hi all,
Im trying to build all the jpa entities out of a legacy database. I have a recurrent problem: some "main" entities have a collection of "translations", where the primary key is the key of the "main" + the "language" identifier. Languages are stored on the database and on an Enum to ease their treatment.
The JPA implementation im using is Hibernate 4.
Hereunder, the current implementation:
Main: (Message)
@Entity
@Table(name="MESSAGES")
@NamedQueries({
public class Message implements Serializable {
@Id
@SequenceGenerator(name="MESSAGES_MESSAGEID_GENERATOR", sequenceName="SEQ_MSG_messageID")
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="MESSAGES_MESSAGEID_GENERATOR")
@Column(name="messageId")
private long id;
@OneToMany(mappedBy="message", fetch=FetchType.EAGER)
private Set<MessageDesc> descriptions;
}
Translation: (MessageDesc)
@Entity
@Table(name="MESSAGEDESCS")
public class MessageDesc implements Serializable, Translatable {
@EmbeddedId
private MessageDescPK id;
@NotNull
@Enumerated(EnumType.ORDINAL)
@Column(name = "LANGUAGEID")
private LanguageEnum language;
@NotNull
@ManyToOne
@JoinColumn(name="MESSAGEID")
private Message message;
}
Translation Compound Key: (MessageDescPK)
@Embeddable
public class MessageDescPK implements Serializable {
@Column(name="messageid", nullable = false, insertable = false)
private long message;
@Column(name="languageid", nullable = false, insertable = false)
private int language;
}
Language: (LanguageEnum)
public enum LanguageEnum {
FRENCH(0, "FR"),
DUTCH(1, "NL");
private int id;
private String desc;
}
The problem is, when trying to persist a Main (Message) entity with some Translations on the descriptions and those translations having the Language and the Message setted, I keep receiving the following exception:
org.springframework.orm.jpa.JpaSystemException: org.hibernate.id.IdentifierGenerationException: null id generated for:class something.persistence.entity.message.MessageDesc; nested exception is javax.persistence.PersistenceException: org.hibernate.id.IdentifierGenerationException: null id generated for:class something.persistence.entity.message.MessageDesc
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:321)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:403)
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:58)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:163)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodIntercceptor.invoke(CrudMethodMetadataPostProcessor.java:111)
I dont understand why the PK is null after setting both the language and the message (already persisted) on the messageDesc instance. Any help, comment, clue will be appreciated.
Thanks!
This is how we solved this issue:
MessageDesc:
@NotNull
@Enumerated(EnumType.ORDINAL)
@Column(name = "LANGUAGEID", insertable=false, nullable = false)
private LanguageEnum language;
@NotNull
@ManyToOne
@JoinColumn(name="MESSAGEID", insertable=false, nullable = false)
private Message message;
@PrePersist
private void prePersist(){
if (getId() == null){
MessageDescPK id = new MessageDescPK();
//the way this enum is persisted is EnumType.ORDINAL
id.setLanguage(getLanguage().ordinal());
id.setMessage(getMessage().getId());
this.setId(id);
}
}
MessageDescPk:
@Embeddable
public class MessageDescPK implements Serializable {
//default serial version id, required for serializable classes.
private static final long serialVersionUID = 1L;
@Column(name="messageid", nullable = false, insertable = false, updatable=false)
private long message;
@Column(name="languageid", nullable = false, insertable = false, updatable=false)
private int language;
Hope this helps :)