JPA @JoinColumn无法正常工作

时间:2015-12-19 14:47:51

标签: java sql hibernate spring-mvc jpa

我有一个应用程序(使用注释的Spring 4 MVC + Hibernate 4 + MySQL + Maven集成示例),使用基于注释的配置将Spring与Hibernate集成。

我有这张桌子

CREATE TABLE `t_device_event` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `device_event_lat` float(10,6) DEFAULT NULL,
  `device_event_lng` float(10,6) DEFAULT NULL,
  `device_id` int(11) unsigned NOT NULL,
  `device_event_message` varchar(100) DEFAULT NULL,
  `device_event_received` TIMESTAMP ,
  `coordinates` point NULL,
  `version` int(11) NULL,
  PRIMARY KEY (`id`),
  KEY `device_id` (`device_id`),
  CONSTRAINT `t_device_event_ibfk_1` FOREIGN KEY (`device_id`) REFERENCES `t_device` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

和这个

CREATE TABLE `t_device` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `device_key` varchar(50) DEFAULT NULL,
  `device_type` varchar(50) DEFAULT NULL,
  `device_desc` varchar(100) DEFAULT NULL,
  `application_id` int(11) unsigned NOT NULL,
  `version` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `application_id` (`application_id`),
  CONSTRAINT `t_device_ibfk_1` FOREIGN KEY (`application_id`) REFERENCES `t_application` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;

此域名对象:

@Entity
@Table(name = "t_device")
@NamedQueries(value = { @NamedQuery(name = "Device.findByKey",
                                    query = "from Device as d where d.key = :key") })
public class Device implements Serializable {

    /**
     *
     */
    private static final long serialVersionUID = -7176158728352557756L;

    private static final Long DEFAULT_VERSION = new Long(0);

    enum Type {
        ANDROID, IOS
    }

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

    @Column(name = "device_key", unique = true, nullable = false)
    private String key;

    @Column(name = "device_desc")
    private String desc;

    @Enumerated(EnumType.STRING)
    @Column(name = "device_type")
    private Type type;

    @OneToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "application_id",
                referencedColumnName = "id")
    private Application application;

    @Version
    @Column(name = "version")
    private Long version = DEFAULT_VERSION;

    /**
     * Instantiates a new device.
     */
    public Device() {
        super();
    }

    /**
     * Instantiates a new device.
     *
     * @param key
     *            the key
     */
    public Device(final String key) {
        super();
        this.key = key;
    }

    /**
     * Gets the id.
     *
     * @return the id
     */
    public Long getId() {
        return id;
    }

    /**
     * Sets the id.
     *
     * @param id
     *            the new id
     */
    public void setId(final Long id) {
        this.id = id;
    }

    /**
     * Gets the key.
     *
     * @return the key
     */
    public String getKey() {
        return key;
    }

    /**
     * Sets the key.
     *
     * @param key
     *            the new key
     */
    public void setKey(final String key) {
        this.key = key;
    }

    /**
     * Gets the desc.
     *
     * @return the desc
     */
    public String getDesc() {
        return desc;
    }

    /**
     * Sets the desc.
     *
     * @param desc
     *            the new desc
     */
    public void setDesc(final String desc) {
        this.desc = desc;
    }

    /**
     * Gets the type.
     *
     * @return the type
     */
    public Type getType() {
        return type;
    }

    /**
     * Sets the type.
     *
     * @param p_type
     *            the new type
     */
    public void setType(final Type p_type) {
        type = p_type;
    }

    /**
     * Gets the application.
     *
     * @return the application
     */
    public Application getApplication() {
        return application;
    }

    /**
     * Sets the application.
     *
     * @param application
     *            the new application
     */
    public void setApplication(final Application application) {
        this.application = application;
    }

    /**
     * Gets the version.
     *
     * @return the version
     */
    public Long getVersion() {
        return version;
    }

    /**
     * Sets the version.
     *
     * @param p_version
     *            the new version
     */
    public void setVersion(final Long p_version) {
        version = p_version;
    }

    /*
     * (non-Javadoc)
     *
     * @see com.yaptechnology.jpa.domain.BaseEntity#equals(java.lang.Object)
     */
    @Override
    public boolean equals(final Object p_obj) {
        boolean isEquals = false;

        try {
            final Device device = (Device) p_obj;
            final EqualsBuilder eb = new EqualsBuilder();

            eb.append(getKey(), device.getKey());
            eb.append(getDesc(), device.getDesc());
            eb.append(getType(), device.getType());

            isEquals = eb.isEquals();
        } catch (final Exception e) {
            isEquals = false;
        }

        return isEquals;
    }

    /*
     * (non-Javadoc)
     *
     * @see com.yaptechnology.jpa.domain.BaseEntity#hashCode()
     */
    @Override
    public int hashCode() {
        final HashCodeBuilder hcb = new HashCodeBuilder();
        hcb.append(getKey());
        hcb.append(getDesc());
        hcb.append(getType());

        return hcb.toHashCode();
    }

    /*
     * (non-Javadoc)
     *
     * @see com.yaptechnology.jpa.domain.BaseEntity#toString()
     */
    @Override
    public String toString() {
        ToStringBuilder tsb = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);

        tsb.append("id", getId());
        tsb.append("key", getKey());
        tsb.append("desc", getDesc());
        tsb.append("type", getType());
        tsb.append("version", getVersion());

        return tsb.toString();
    }

}
另一个:

@Entity
@Table(name = "t_device_event")
public class DeviceEvent {

    private static final Long DEFAULT_VERSION = new Long(0);

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

    @ManyToOne
    @JoinColumn(name = "device_id")
    private Device device;

    @Column(name = "device_event_received")
    private Long received;

    @Column(name = "device_event_message")
    private String message;

    @Version
    @Column(name = "version")
    private Long version = DEFAULT_VERSION;

    @Embedded
    private Coordinates coordinates;

    /**
     * Instantiates a new device event.
     *
     * @param device
     *            the device
     */
    public DeviceEvent(final Device device) {
        super();
        this.device = device;
    }

    /**
     * Gets the coordinates.
     *
     * @return the coordinates
     */
    public Coordinates getCoordinates() {
        return coordinates;
    }

    /**
     * Sets the coordinates.
     *
     * @param coordinates
     *            the new coordinates
     */
    public void setCoordinates(final Coordinates coordinates) {
        this.coordinates = coordinates;
    }

    /**
     * Gets the id.
     *
     * @return the id
     */
    public Long getId() {
        return id;
    }

    /**
     * Sets the id.
     *
     * @param id
     *            the new id
     */
    public void setId(final Long id) {
        this.id = id;
    }

    /**
     * Gets the device.
     *
     * @return the device
     */
    public Device getDevice() {
        return device;
    }

    /**
     * Sets the device.
     *
     * @param device
     *            the new device
     */
    public void setDevice(final Device device) {
        this.device = device;
    }

    /**
     * Gets the received.
     *
     * @return the received
     */
    public Long getReceived() {
        return received;
    }

    /**
     * Sets the received.
     *
     * @param received
     *            the new received
     */
    public void setReceived(final Long received) {
        this.received = received;
    }

    /**
     * Gets the message.
     *
     * @return the message
     */
    public String getMessage() {
        return message;
    }

    /**
     * Sets the message.
     *
     * @param message
     *            the new message
     */
    public void setMessage(final String message) {
        this.message = message;
    }

    /**
     * Gets the version.
     *
     * @return the version
     */
    public Long getVersion() {
        return version;
    }

    /**
     * Sets the version.
     *
     * @param p_version
     *            the new version
     */
    public void setVersion(final Long p_version) {
        version = p_version;
    }


    /*
     * (non-Javadoc)
     *
     * @see com.yaptechnology.jpa.domain.BaseEntity#equals(java.lang.Object)
     */
    @Override
    public boolean equals(final Object p_obj) {
        boolean isEquals = false;

        try {
            final DeviceEvent deviceEvent = (DeviceEvent) p_obj;
            final EqualsBuilder eb = new EqualsBuilder();

            eb.append(getReceived(), deviceEvent.getReceived());
            eb.append(getMessage(), deviceEvent.getMessage());
            eb.append(getDevice(), deviceEvent.getDevice());

            isEquals = eb.isEquals();
        } catch (final Exception e) {
            isEquals = false;
        }

        return isEquals;
    }

    /*
     * (non-Javadoc)
     *
     * @see com.yaptechnology.jpa.domain.BaseEntity#hashCode()
     */
    @Override
    public int hashCode() {
        final HashCodeBuilder hcb = new HashCodeBuilder();
        hcb.append(getReceived());
        hcb.append(getMessage());
        hcb.append(getDevice());

        return hcb.toHashCode();
    }

    /*
     * (non-Javadoc)
     *
     * @see com.yaptechnology.jpa.domain.BaseEntity#toString()
     */
    @Override
    public String toString() {
        ToStringBuilder tsb = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);

        tsb.append("id", getId());
        tsb.append("received", getReceived());
        tsb.append("message", getMessage());
        tsb.append("device", getDevice());
        tsb.append("coordinates", getCoordinates());
        tsb.append("version", getVersion());

        return tsb.toString();
    }

}

这在控制器中:

Device device = deviceService.findByKey("de305d54-75b4-431b-adb2-eb6b9e546014");

        LOGGER.debug("device: {}", device);

        DeviceEvent deviceEvent = new DeviceEvent(device);
        deviceEvent.setCoordinates(new Coordinates((double)30.8340150, (double)2.3778850));
        deviceEvent.setMessage("message");
        deviceEventService.save(deviceEvent);

但是我保存时出现了这个错误

com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Column 'device_id' cannot be null
    sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
    sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    java.lang.reflect.Constructor.newInstance(Constructor.java:526)
    com.mysql.jdbc.Util.handleNewInstance(Util.java:404)
    com.mysql.jdbc.Util.getInstance(Util.java:387)
    com.mysql.jdbc.SQLError.createSQLException(SQLError.java:934)
    com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3870)
    com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3806)
    com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2470)
    com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2617)
    com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2550)
    com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1861)
    com.mysql.jdbc.PreparedStatement.executeUpdateInternal(PreparedStatement.java:2073)
    com.mysql.jdbc.PreparedStatement.executeUpdateInternal(PreparedStatement.java:2009)
    com.mysql.jdbc.PreparedStatement.executeLargeUpdate(PreparedStatement.java:5094)
    com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1994)
    org.apache.tomcat.dbcp.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:105)
    org.apache.tomcat.dbcp.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:105)
    org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:204)
    org.hibernate.id.IdentityGenerator$GetGeneratedKeysDelegate.executeAndExtract(IdentityGenerator.java:84)
    org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:42)
    org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2792)
    org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3362)
    org.hibernate.action.internal.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:81)
    org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:597)
    org.hibernate.engine.spi.ActionQueue.addResolvedEntityInsertAction(ActionQueue.java:232)
    org.hibernate.engine.spi.ActionQueue.addInsertAction(ActionQueue.java:213)
    org.hibernate.engine.spi.ActionQueue.addAction(ActionQueue.java:256)
    org.hibernate.event.internal.AbstractSaveEventListener.addInsertAction(AbstractSaveEventListener.java:317)
    org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:272)
    org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:178)
    org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:109)
    org.hibernate.jpa.event.internal.core.JpaPersistEventListener.saveWithGeneratedId(JpaPersistEventListener.java:67)
    org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:189)
    org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:132)
    org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:58)
    org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:775)
    org.hibernate.internal.SessionImpl.persist(SessionImpl.java:748)
    org.hibernate.internal.SessionImpl.persist(SessionImpl.java:753)
    org.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1146)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    java.lang.reflect.Method.invoke(Method.java:606)
    org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:293)
    com.sun.proxy.$Proxy107.persist(Unknown Source)
    fr.telecom.dao.impl.AbstractDao.persist(AbstractDao.java:91)
    fr.telecom.service.impl.DeviceEventServiceImpl.save(DeviceEventServiceImpl.java:25)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    java.lang.reflect.Method.invoke(Method.java:606)
    org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:302)
    org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
    org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
    org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
    org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
    org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
    org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208)
    com.sun.proxy.$Proxy112.save(Unknown Source)
    fr.telecom.controller.AppController.listDevices(AppController.java:63)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    java.lang.reflect.Method.invoke(Method.java:606)
    org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:222)
    org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
    org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:814)
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:737)
    org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
    org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
    org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
    org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:624)
    org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
    org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:121)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    org.springframework.web.multipart.support.MultipartFilter.doFilterInternal(MultipartFilter.java:118)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)

1 个答案:

答案 0 :(得分:1)

首先需要保存设备,以便可以将FK插入到device_event表中。您可以通过添加如下的级联选项让框架为您执行此操作。

@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "device_id")
private Device device;