CodeMed
CodeMed

Reputation: 9191

Hibernate throws SQLException "id field does not have a default value"

In a spring mvc app using hibernate, I am encountering the following error when i try to persist an entity:

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

The database schema is generated by hbm2ddl. How can I change the hibernate code so that these entities can be persisted successfully?

The two entities are AClass and HClass. The code for AClass is::

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;}

}

The code for HClass is:

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;}

}

The controller code that triggers the error is:

@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);
}

Note that the line of code in the controller above that triggers the error is:

this.serviceLayer.saveAClass(ac);

The repository code finally called by the service layer is:

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

The complete stack trace is:

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

ANSWER


The solution came from the part of @VladMihalcea's answer that involved removing the multiple references to HClass in the list of properties of AClass. Specifically, I created types HClassFirst, HClassSecond, and HClassThird, all with the same properties and methods. This way, hibernate did not get confused by multiple properties of AClass linking to the same type. The app's architecture allows for this. I decided against using inheritance because there are already a lot of links in each table, and I don't want to bump into other errors related to an excess number of foreign keys.

Thus, the solution was not in hibernate annotations. Instead, the solution was in adjusting the model that hibernate is being asked to persist.

Upvotes: 2

Views: 5124

Answers (2)

Vlad Mihalcea
Vlad Mihalcea

Reputation: 153780

I think it's much simpler to use cascading in this example:

@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;}

}

Then the persisting logic becomes just that:

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

The original issue might be due to this:

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

This is how you should initialize collections in your entities:

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

So, when you want to modify the collections, you don't reset them, but rather rely on the dirty checking mechanism to add/remove elements:

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);

During a merge, you should remove the children that no longer belong to a parent and add the new ones coming from your web request.

Edit

I tried your example on my local machine and like the problem is the way you do the mappings. Because you link the Aclass with HClass on 3 different relations (one many-to-one and 2 one-to-many), this is what you get:

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

So when you try to enter an entity:

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

The only fix is to change the Mapping. Instead of 3 HClass associations you should have something else, maybe an inheritance model or something. Always try to model your domain entities on a valid schema.

Upvotes: 3

PWC
PWC

Reputation: 266

the "persist detached entity error" is because new transaction is opened for each persist action. For new opened transaction, the entity persisted(the HCClass) in last transaction become "detached". I suggest you group all you persist action in one transaction, you can do it by move persistAClass to service layer and annotate it @Transactional.

Upvotes: 1

Related Questions