Ad

Many-to-Many With Extra Column (Hibernate 4)

- 1 answer

I know In order to have extra column on many-to-many relationship, I need to create a new table and a new class for that. The problem is I cannot save my entity. The id is null. Have no ideal how to solve it. The following is my entities:

@Entity
@Table(name = "sms_history")
public class SmsHistory implements Serializable {

private static final long serialVersionUID = 56345093485043L;

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

@NotNull
private String subject;

@NotNull
private Date sendDate;

@NotNull
private String body;

@OneToMany(mappedBy = "smsHistory", fetch = FetchType.LAZY, cascade= CascadeType.ALL)
private List<SmsHistoryRecipient> smsHistoryRecipients = new ArrayList<>();

SmsHistoryRecipient Class:

@Entity
@Table(name = "sms_history_recipient")
@IdClass(SmsHistoryRecipientId.class)
public class SmsHistoryRecipient implements Serializable {

/**
 * 
 */
private static final long serialVersionUID = 8812931823010L;

@Id
@Column(name="sms_history_id")
private Long smsHistoryId;

@Id
@Column(name="recipient_id")
private Long recipientId;

@ManyToOne
@JoinColumn(name="sms_history_id",  updatable = false, insertable = false, referencedColumnName = "id")
private SmsHistory smsHistory;

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name="recipient_id",  updatable = false, insertable = false, referencedColumnName = "id")
private Recipient recipient;

@Column(name = "send_datetime")
private Timestamp sendDatetime;

@Column(name = "success", columnDefinition = "BIT")
private boolean success;

SmsHistoryRecipientId class:

@Embeddable
public class SmsHistoryRecipientId implements Serializable { 

/**
 * 
 */
private static final long serialVersionUID = 453432423L;

@Column(name="sms_history_id")
private Long smsHistoryId;

@Column(name="recipient_id")
private Long recipientId;

Controller (save the Entity):

@Autowired
RecipientService recipient;

@RequestMapping("/sendSms")
public void sendSms(@RequestParam(value="content") String body, @RequestParam(value="subject") String subject) {
    List<Recipient> recipients = recipient.findAll();
    SmsHistory smsHistory = new SmsHistory();

    //Set values
    smsHistory.setSubject(subject);
    smsHistory.setSendDate(new Date(Calendar.getInstance().getTimeInMillis()));
    smsHistory.setBody(body);

    for(Recipient recipient: recipients) {
        SmsHistoryRecipient smsHistoryRecipient = new SmsHistoryRecipient();
        smsHistoryRecipient.setRecipient(recipient);
        smsHistoryRecipient.setRecipientId(recipient.getId());

        smsHistoryRecipient.setSmsHistory(smsHistory);
        Timestamp currentDateTime = new Timestamp(Calendar.getInstance().getTimeInMillis());
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String DateToStr = format.format(currentDateTime);
        System.out.println(DateToStr);
        smsHistoryRecipient.setSendDatetime(currentDateTime);

        smsHistoryRecipient.setSuccess(true);
        smsHistory.getSmsHistoryRecipients().add(smsHistoryRecipient);
   }
    smsHistoryService.save(smsHistory);
}

Repository:

public interface SmsHistoryRepository extends JpaRepository<SmsHistory, Long> {

}

@Service
public class SmsHistoryService {

@Autowired
private SmsHistoryRepository smsHistoryRepository;

public SmsHistory findOne(Long id) {
    return smsHistoryRepository.findOne(id);
}

public List<SmsHistory> findAll() {
    return smsHistoryRepository.findAll();
}

public long count() {
    return smsHistoryRepository.count();
}

public void save(SmsHistory smsHistory) {
    smsHistoryRepository.save(smsHistory);
}

public void delete(SmsHistory smsHistory) {
    smsHistoryRepository.delete(smsHistory);
}

}

The Error:

com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Column 'sms_history_id' cannot be null
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:404)
at com.mysql.jdbc.Util.getInstance(Util.java:387)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:934)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3870)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3806)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2470)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2617)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2550)
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1861)
at com.mysql.jdbc.PreparedStatement.executeUpdateInternal(PreparedStatement.java:2073)
at com.mysql.jdbc.PreparedStatement.executeUpdateInternal(PreparedStatement.java:2009)
at com.mysql.jdbc.PreparedStatement.executeLargeUpdate(PreparedStatement.java:5094)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1994)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:208)
at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:62)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3124)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3581)
at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:104)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:465)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:351)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:350)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:56)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1258)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:425)
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)
at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:177)
at org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:77)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:517)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:757)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:726)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:521)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:291)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodIntercceptor.invoke(CrudMethodMetadataPostProcessor.java:122)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
at com.sun.proxy.$Proxy71.save(Unknown Source)
at tsl.steel.service.SmsHistoryService.save(SmsHistoryService.java:30)
at tsl.steel.controller.SendSmsController.sendSms(SendSmsController.java:79)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:775)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:705)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:967)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:869)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:648)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:843)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:85)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:217)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:673)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1500)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1456)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
Ad

Answer

Try the following.

@Entity
@Table(name = "sms_history")
public class SmsHistory implements Serializable {

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

@OneToMany(mappedBy = "smsHistory", fetch = FetchType.LAZY, cascade= CascadeType.ALL)
private List<SmsHistoryRecipient> smsHistoryRecipients = new ArrayList<>();
...

The following class will have the embeddable SmsHistoryRecipientId as it's primary key.

@Entity
@Table(name = "sms_history_recipient")
public class SmsHistoryRecipient implements Serializable {

@EmbeddedId
private SmsHistoryRecipientId smsHistoryRecipientId;

...

Below is the Embeddable class.

@Embeddable
public class SmsHistoryRecipientId implements Serializable { 

@ManyToOne
@JoinColumn(name="sms_history_id",  updatable = false, insertable = false, referencedColumnName = "id")
private SmsHistory smsHistoryId;

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name="recipient_id",  updatable = false, insertable = false, referencedColumnName = "id")
private Recipient recipient;

Hope this helps.

Ad
source: stackoverflow.com
Ad