2011-11-22 13 views
6

ho un rapporto padre-figlio:Hibernate: Save Parent automaticamente prima di risparmio del bambino

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

Qui User è la controllante e News è il bambino. Il motivo per cui ho le operazioni in cascata è perché voglio che tutti gli oggetti News vengano cancellati/persistenti quando elimino/persistono il corrispondente User. Inoltre, quando persisto un oggetto News, desidero che il corrispondente User sia mantenuto [ma non eliminato se lo News viene eliminato]. Ho un metodo di servizio che salva un oggetto News come segue:

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

session.save(n); 

Per il codice di cui sopra ottengo la seguente eccezione:

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 

Quale potrebbe essere il problema qui?

Sono errato nell'avere un metodo di servizio che tenta di salvare un bambino? Dovrei sempre salvare il genitore, invece?

Grazie.

AGGIORNAMENTO: Se si salva invece l'utente come session.save(u) anziché le notizie, è tutto a posto. Quindi la domanda che rimane è, è errato salvare il bambino invece del genitore? In caso contrario, come posso ottenerlo?

+0

hai provato ** session.save (u) ** invece? – ManuPK

+1

@ManuPK Se uso 'session.save (u)' allora tutto va bene. Sto chiedendo è errato se faccio 'session.save (n)'? Se non è corretto, come faccio? –

risposta

6

quello che dovete fare seguenti things.These sono: - l'opzione cascade

  • Rimuovi dal lato notizia.
  • Nel tuo caso di utilizzo hai notizie nuove di zecca e nuovo utente. Perché tu, , vuoi persistere notizie. Oggetto utente persistente. Entrambi saranno persistenti.
  • In un altro caso di utilizzo in cui si dispone di un utente esistente e si desidera aggiungere una nuova notizia. Nell'implementazione service/dao creare un metodo per mantenere l'oggetto news che passa l'id utente. Quindi puoi usare caricare/associare l'uso e mantenere la notizia
+0

Quindi per rispondere esplicitamente alla domanda dell'OP nel commento: 'session.save (n)' non è corretto. – Stewart

1

Credo che non sia necessario impostare la cascata sul lato figlio. Basta avere Cascade.ALL sul lato genitore (User.news) dovrebbe essere sufficiente.

Un'altra cosa, se cancellerai le notizie quando l'utente viene cancellato (come hai detto nel tuo post), credo che sia necessario aggiungere il tipo di cascata Elimina orfano anche dal lato genitore.

Problemi correlati