Sleep mode: automatically save the parent before saving the child

I have a parent-child relationship:

@Entity @Table(name = "user") public final class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer userID; @Column(name = "username") private String userName; @OneToMany(cascade = CascadeType.ALL, mappedBy = "admin") private Set<News> news; } @Entity @Table(name = "news") public final class News { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int newsID; @ManyToOne(cascade = CascadeType.PERSIST) @JoinColumn(name = "userID") private User admin; @Column(name = "newsText") private String newsText; @Column(name = "dateOfPost") private Date dateOfPost; } 

Here User is the parent, and News is the child. The reason I have cascading operations is because I want all News objects to be deleted / saved when I delete / save the corresponding User . Also, when I save the News object, I want the corresponding User saved (but not deleted if News deleted). I have a service method that saves a News object as follows:

 User u = new User("administrator"); News n = new News("News text"); n.setUser(u); u.addNews(n); session.save(n); 

For the above code, I get the following exception:

 org.hibernate.exception.ConstraintViolationException: could not insert: [com.maximus.db.model.News] at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96) at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66) at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:64) at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2345) at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2852) at org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:71) at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:273) at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:320) at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:203) at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:129) at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210) at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:56) at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195) at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:50) at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93) at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:713) at org.hibernate.impl.SessionImpl.save(SessionImpl.java:701) at org.hibernate.impl.SessionImpl.save(SessionImpl.java:697) at com.maximus.db.dao.NewsDAOImpl.addNews(NewsDAOImpl.java:17) at com.maximus.db.service.NewsServiceImpl.addNews(NewsServiceImpl.java:31) at com.maximus.test.db.service.NewsServiceTest.testAddNewsWithNewUser(NewsServiceTest.java:36) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at org.junit.internal.runners.TestMethodRunner.executeMethodBody(TestMethodRunner.java:99) at org.junit.internal.runners.TestMethodRunner.runUnprotected(TestMethodRunner.java:81) at org.junit.internal.runners.BeforeAndAfterRunner.runProtected(BeforeAndAfterRunner.java:34) at org.junit.internal.runners.TestMethodRunner.runMethod(TestMethodRunner.java:75) at org.junit.internal.runners.TestMethodRunner.run(TestMethodRunner.java:45) at org.junit.internal.runners.TestClassMethodsRunner.invokeTestMethod(TestClassMethodsRunner.java:66) at org.junit.internal.runners.TestClassMethodsRunner.run(TestClassMethodsRunner.java:35) at org.junit.internal.runners.TestClassRunner$1.runUnprotected(TestClassRunner.java:42) at org.junit.internal.runners.BeforeAndAfterRunner.runProtected(BeforeAndAfterRunner.java:34) at org.junit.internal.runners.TestClassRunner.run(TestClassRunner.java:52) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Column 'userId' cannot be null at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source) at java.lang.reflect.Constructor.newInstance(Unknown Source) at com.mysql.jdbc.Util.handleNewInstance(Util.java:409) at com.mysql.jdbc.Util.getInstance(Util.java:384) at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1041) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3566) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3498) at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1959) at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2113) at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2568) at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2113) at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2409) at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2327) at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2312) at org.hibernate.id.IdentityGenerator$GetGeneratedKeysDelegate.executeAndExtract(IdentityGenerator.java:94) at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:57) ... 38 more 

What could be the problem?

Am I using a service method that is trying to save a child? Should I always keep the parent instead?

Thanks.

UPDATE: If instead of this I instead save the user, I save the user as session.save(u) , everything is in order. Thus, the question remains: is it right to save the child instead of the parent? If not, how can I achieve it?

+6
source share
2 answers

You must do the following things. It: -

  • Remove cascade option from news.
  • In your use case, you have a new news item and a new user. Why do you want to save the news item. Persist user object. Both will be saved.
  • In another case, when you have an existing user and you want to add new news material. In the service / dao implementation, create a method to store the news object that passes the user ID. You can then use upload / receive to link use and save the news item
+6
source

I believe that you do not need to cascade on the child side. Just Cascade.ALL on the parent side (User.news) should be enough.

One more thing, if you are going to delete news when the user is deleted (as indicated in your message), I believe that you need to add the cascading type Delete Orphan on the parent side.

+1
source

Source: https://habr.com/ru/post/902115/


All Articles