Hibernate抛出SQLException“id字段没有默认值”

时间:2015-04-28 19:24:22

标签: java spring hibernate jpa orm

在使用hibernate的spring mvc app中,当我尝试持久化实体时遇到以下错误:

java.sql.SQLException: Field 'thirdIds_huid' doesn't have a default value

数据库架构由hbm2ddl生成。如何更改hibernate代码以便可以成功保存这些实体?

这两个实体是AClassHClassAClass的代码是::

import javax.persistence.*;

@Entity(name = "AClass")
@Table(name = "a_class")
public class AClass {

    private Long auid;  
    private HClass firstId;
    private List<HClass> secondIds;
    private List<HClass> thirdIds;

    @Id
    @Column(name = "auid")
    @GeneratedValue(strategy = GenerationType.AUTO)
    public Long getAuid(){return auid;}
    public void setAuid(Long hid){auid = hid;}

    @ManyToOne
    public HClass getFirstId(){return firstId;}
    public void setFirstId(HClass tid){firstId = tid;}

    @OneToMany
    public List<HClass> getSecondIds(){return secondIds;}
    public void setSecondIds(List<HClass> tid){secondIds = tid;}

    @OneToMany
    public List<HClass> getThirdIds(){return thirdIds;}
    public void setThirdIds(List<HClass> i){thirdIds = i;}

}

HClass的代码是:

import javax.persistence.*;

@Entity(name = "HClass")
@Table(name = "h_class")
public class HClass {

    private Long huid;
    private String somefield;

    @Id
    @Column(name = "huid")
    @GeneratedValue(strategy = GenerationType.AUTO)
    public Long getHuid(){return huid;}
    public void setHuid(Long hid){huid = hid;}

    @Column(name = "somefield")
    public String getSomefield(){return somefield;}
    public void setSomefield(String rt){somefield = rt;}

}

触发错误的控制器代码是:

@RequestMapping(value = "/TriggerTheError", method = RequestMethod.GET)
public String processFindForm( HttpServletRequest request, Map<String, Object> model) {     
    AClass ac = new AClass();
    HClass hc = new HClass();
    hc.setSomefield("some value goes here");
    List<HClass> hcs = new ArrayList<HClass>();
    hcs.add(hc);
    ac.setSecondIds(hcs);

    HClass hc2 = new HClass();
    hc2.setSomefield("another value goes here");
    List<HClass> hcs2 = new ArrayList<HClass>();
    hcs2.add(hc2);
    ac.setThirdIds(hcs2);

    persistAClass(ac);
    return "ReproduceError";
}

public void persistAClass(AClass ac){

    if(ac.getThirdIds()!=null){
        if(ac.getThirdIds().size()==0){ac.setThirdIds(null);System.out.println("thirdids re-set to null.");}
        if(ac.getThirdIds()!=null){
            System.out.println("thirdids!=null: size is: "+ac.getThirdIds().size());
            for(int dd = 0;dd<ac.getThirdIds().size();dd++){
                this.serviceLayer.saveHClass(ac.getThirdIds().get(dd));
            }
        }
    }
    if(ac.getSecondIds()!=null){
        if(ac.getSecondIds().size()==0){ac.setSecondIds(null);System.out.println("secondids re-set to null.");}
        if(ac.getSecondIds()!=null){
            System.out.println("secondsid!=null: size is:"+ac.getSecondIds().size());
            for(int kk = 0;kk < ac.getSecondIds().size();kk++){
                this.serviceLayer.saveHClass(ac.getSecondIds().get(kk));
            }
        }
    }
    if(ac.getFirstId()!=null){
        System.out.println("firstid!=null: huid value is: "+ac.getFirstId().getHuid());
        this.serviceLayer.saveHClass(ac.getFirstId());
    }

System.out.println("-------------------- data follows ------------------------------");
    for(int a=0;a<ac.getSecondIds().size();a++){
        System.out.println("a, secondids somefield are: "+a+", "+ac.getSecondIds().get(a).getSomefield());
    }
    if(ac.getFirstId()!=null){
        String rt = "";
        if(ac.getFirstId().getSomefield()!=null){rt = ac.getFirstId().getSomefield();}
        System.out.println("first id some field is: "+rt);
    }
    if(ac.getThirdIds()!=null){
        for(int b = 0;b<ac.getThirdIds().size();b++){
            String sf = "";
            if(ac.getThirdIds().get(b).getSomefield()!=null){sf = ac.getThirdIds().get(b).getSomefield();}
            System.out.println("b, third ids somefield are: "+b+", "+sf);
        }
    }
System.out.println("-------------------- end of data -------------------------------");
    this.serviceLayer.saveAClass(ac);
}

请注意,上面控制器中触发错误的代码行是:

this.serviceLayer.saveAClass(ac);

服务层最终调用的存储库代码是:

@Override
public void saveAClass(AClass myac) throws DataAccessException{
    if (myac.getAuid() == null) {this.em.persist(myac);}
    else {this.em.merge(myac);}
 }

完整的堆栈跟踪是:

11:51:04.334 [http-nio-8080-exec-3] DEBUG o.s.web.servlet.DispatcherServlet - Handler execution resulted in exception - forwarding to resolved error view: ModelAndView: reference to view with name 'exception'; model is {exception=org.springframework.orm.hibernate3.HibernateJdbcException: JDBC exception on Hibernate data access: SQLException for SQL [n/a]; SQL state [HY000]; error code [1364]; could not execute statement; nested exception is org.hibernate.exception.GenericJDBCException: could not execute statement}
org.springframework.orm.hibernate3.HibernateJdbcException: JDBC exception on Hibernate data access: SQLException for SQL [n/a]; SQL state [HY000]; error code [1364]; could not execute statement; nested exception is org.hibernate.exception.GenericJDBCException: could not execute statement
    at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:651) ~[spring-orm-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:106) ~[spring-orm-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:517) ~[spring-orm-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:755) ~[spring-tx-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:724) ~[spring-tx-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:475) ~[spring-tx-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:270) ~[spring-tx-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94) ~[spring-tx-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) ~[spring-aop-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204) ~[spring-aop-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at com.sun.proxy.$Proxy27.saveAClass(Unknown Source) ~[na:na]
    at example.controller.SomeModelClassController.persistAClass(SomeModelClassController.java:96) ~[SomeModelClassController.class:na]
    at example.controller.SomeModelClassController.processFindForm(SomeModelClassController.java:50) ~[SomeModelClassController.class:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.7.0_79]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) ~[na:1.7.0_79]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.7.0_79]
    at java.lang.reflect.Method.invoke(Method.java:606) ~[na:1.7.0_79]
    at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:219) ~[spring-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132) ~[spring-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104) ~[spring-webmvc-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:745) ~[spring-webmvc-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:686) ~[spring-webmvc-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80) ~[spring-webmvc-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925) [spring-webmvc-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856) [spring-webmvc-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:936) [spring-webmvc-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:827) [spring-webmvc-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:618) [servlet-api.jar:na]
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:812) [spring-webmvc-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:725) [servlet-api.jar:na]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291) [catalina.jar:8.0.15]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [catalina.jar:8.0.15]
    at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77) [spring-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) [catalina.jar:8.0.15]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [catalina.jar:8.0.15]
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) [tomcat-websocket.jar:8.0.15]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) [catalina.jar:8.0.15]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [catalina.jar:8.0.15]
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88) [spring-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) [catalina.jar:8.0.15]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [catalina.jar:8.0.15]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219) [catalina.jar:8.0.15]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106) [catalina.jar:8.0.15]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501) [catalina.jar:8.0.15]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142) [catalina.jar:8.0.15]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) [catalina.jar:8.0.15]
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:610) [catalina.jar:8.0.15]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88) [catalina.jar:8.0.15]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:537) [catalina.jar:8.0.15]
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1085) [tomcat-coyote.jar:8.0.15]
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:658) [tomcat-coyote.jar:8.0.15]
    at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:222) [tomcat-coyote.jar:8.0.15]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1556) [tomcat-coyote.jar:8.0.15]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1513) [tomcat-coyote.jar:8.0.15]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [na:1.7.0_79]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [na:1.7.0_79]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-util.jar:8.0.15]
    at java.lang.Thread.run(Thread.java:745) [na:1.7.0_79]
Caused by: org.hibernate.exception.GenericJDBCException: could not execute statement
    at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:54) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:125) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:110) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]
    at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:136) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]
    at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:58) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]
    at org.hibernate.persister.collection.AbstractCollectionPersister.recreate(AbstractCollectionPersister.java:1256) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]
    at org.hibernate.action.internal.CollectionRecreateAction.execute(CollectionRecreateAction.java:58) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]
    at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:364) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:356) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:281) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]
    at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:328) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]
    at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:52) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]
    at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1234) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]
    at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:404) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]
    at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]
    at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:175) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]
    at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:75) ~[hibernate-entitymanager-4.2.1.Final.jar:4.2.1.Final]
    at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:513) ~[spring-orm-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    ... 57 common frames omitted
Caused by: java.sql.SQLException: Field 'thirdIds_huid' doesn't have a default value
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1078) ~[mysql-connector-java-5.1.27.jar:na]
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4237) ~[mysql-connector-java-5.1.27.jar:na]
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4169) ~[mysql-connector-java-5.1.27.jar:na]
    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2617) ~[mysql-connector-java-5.1.27.jar:na]
    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2778) ~[mysql-connector-java-5.1.27.jar:na]
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2825) ~[mysql-connector-java-5.1.27.jar:na]
    at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2156) ~[mysql-connector-java-5.1.27.jar:na]
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2459) ~[mysql-connector-java-5.1.27.jar:na]
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2376) ~[mysql-connector-java-5.1.27.jar:na]
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2360) ~[mysql-connector-java-5.1.27.jar:na]
    at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:133) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]
    ... 71 common frames omitted
11:51:04.336 [http-nio-8080-exec-3] DEBUG o.s.w.s.v.ContentNegotiatingViewResolver - Requested media types are [text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8] based on Accept header types and producible media types [*/*])
11:51:04.336 [http-nio-8080-exec-3] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Invoking afterPropertiesSet() on bean with name 'exception'
11:51:04.337 [http-nio-8080-exec-3] DEBUG o.s.w.s.v.ContentNegotiatingViewResolver - Returning [org.springframework.web.servlet.view.JstlView: name 'exception'; URL [/WEB-INF/jsp/exception.jsp]] based on requested media type 'text/html'
11:51:04.337 [http-nio-8080-exec-3] DEBUG o.s.web.servlet.DispatcherServlet - Rendering view [org.springframework.web.servlet.view.JstlView: name 'exception'; URL [/WEB-INF/jsp/exception.jsp]] in DispatcherServlet with name 'MinimalDbaseExample'
11:51:04.337 [http-nio-8080-exec-3] DEBUG o.s.web.servlet.view.JstlView - Added model object 'exception' of type [org.springframework.orm.hibernate3.HibernateJdbcException] to request in view with name 'exception'
11:51:04.337 [http-nio-8080-exec-3] DEBUG o.s.web.servlet.view.JstlView - Forwarding to resource [/WEB-INF/jsp/exception.jsp] in InternalResourceView 'exception'
11:51:04.380 [http-nio-8080-exec-3] DEBUG o.s.web.servlet.DispatcherServlet - Successfully completed request

答案

解决方案来自@ VladMihalcea的回答,其中涉及删除HClass属性列表中对AClass的多个引用。具体来说,我创建了类型HClassFirstHClassSecondHClassThird,它们都具有相同的属性和方法。这样,hibernate就不会被链接到同一类型的AClass的多个属性所迷惑。应用程序的架构允许这样做。我决定不使用继承,因为每个表中已经有很多链接,我不想碰到与过多外键相关的其他错误。

因此,该解决方案不在休眠注释中。相反,解决方案是调整hibernate被要求持久的模型。

2 个答案:

答案 0 :(得分:3)

我认为这个例子中的much simpler to use cascading

@Entity(name = "AClass")
@Table(name = "a_class")
public class AClass {

    private Long auid;  
    private HClass firstId;
    private List<HClass> secondIds = new ArrayList<>();
    private List<HClass> thirdIds = new ArrayList<>();

    @Id
    @Column(name = "auid")
    @GeneratedValue(strategy = GenerationType.AUTO)
    public Long getAuid(){return auid;}
    public void setAuid(Long hid){auid = hid;}

    @ManyToOne
    public HClass getFirstId(){return firstId;}
    public void setFirstId(HClass tid){firstId = tid;}

    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
    public List<HClass> getSecondIds(){return secondIds;}
    public void setSecondIds(List<HClass> tid){secondIds = tid;}

    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
    public List<HClass> getThirdIds(){return thirdIds;}
    public void setThirdIds(List<HClass> i){thirdIds = i;}

}

然后,持久性逻辑变为:

public void persistAClass(AClass ac){    
    this.serviceLayer.saveAClass(ac);
}

原始问题可能是由于:

at org.hibernate.action.internal.CollectionRecreateAction.execute(CollectionRecreateAction.java:58) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]

这是您应该在实体中初始化集合的方式:

private List<HClass> secondIds = new ArrayList<>();
private List<HClass> thirdIds = new ArrayList<>();

因此,当您想要修改集合时,您不会重置它们,而是依靠dirty checking mechanism添加/删除元素:

AClass ac = new AClass();
HClass hc = new HClass();
hc.setSomefield("some value goes here");

ac.getSecondIds().add(hc);

HClass hc2 = new HClass();
hc2.setSomefield("another value goes here");
ac.getThirdIds().add(hc2);

persistAClass(ac);

在合并期间,您应该删除不再属于父级的子级,并添加来自Web请求的新子级。

修改

我在我的本地机器上尝试了你的例子,问题就是你做映射的方式。因为您将Aclass与HClass链接在3个不同的关系(一对多和一对多)上,这就是您所得到的:

create table a_class (auid bigint generated by default as identity (start with 1), firstId_huid bigint, primary key (auid))
create table a_class_h_class (a_class_auid bigint not null, thirdIds_huid bigint not null, secondIds_huid bigint not null)
create table h_class (huid bigint generated by default as identity (start with 1), somefield varchar(255), primary key (huid))
alter table a_class_h_class add constraint UK_qtt8gi008ssnfi4t3mo3tq310  unique (thirdIds_huid)
alter table a_class_h_class add constraint UK_35k583bmbiomo0rc6t74ba41g  unique (secondIds_huid)
alter table a_class add constraint FK_1hw1d6sy2yhp9hirqgb6rx6yr foreign key (firstId_huid) references h_class
alter table a_class_h_class add constraint FK_qtt8gi008ssnfi4t3mo3tq310 foreign key (thirdIds_huid) references h_class
alter table a_class_h_class add constraint FK_jng9ogc4rmlmojd31weygk6l9 foreign key (a_class_auid) references a_class
alter table a_class_h_class add constraint FK_35k583bmbiomo0rc6t74ba41g foreign key (secondIds_huid) references h_class

因此,当您尝试输入实体时:

Query:{[insert into a_class (auid, firstId_huid) values (default, ?)][-5]} 
Query:{[insert into h_class (huid, somefield) values (default, ?)][some value goes here]} 
Query:{[insert into h_class (huid, somefield) values (default, ?)][another value goes here]} 
Query:{[insert into a_class_h_class (a_class_auid, secondIds_huid) values (?, ?)][1,1]} 
WARN  [Alice]: o.h.e.j.s.SqlExceptionHelper - SQL Error: -10, SQLState: 23502
ERROR [Alice]: o.h.e.j.s.SqlExceptionHelper - integrity constraint violation: NOT NULL check constraint; SYS_CT_10096 table: A_CLASS_H_CLASS column: THIRDIDS_HUID

唯一的解决方法是更改​​映射。而不是3个HClass关联,你应该有别的东西,可能是继承模型或其他东西。始终尝试在有效架构上建模您的域实体。

答案 1 :(得分:1)

“持久性分离实体错误”是因为为每个持久性操作打开了新事务。对于新打开的事务,最后一个事务中持久化的实体(HCClass)变为“分离”。 我建议你在一个事务中对所有持久化操作进行分组,你可以通过将persistAClass移动到服务层并将其注释为@Transactional来实现。