2011-11-22 9 views
6

tengo una relación padre-hijo:Hibernate: Guardar automáticamente antes de Padres del ahorro del niño

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

Aquí User es el padre y el niño es News. La razón por la que tengo las operaciones en cascada es porque quiero que todos los objetos News se eliminen/persistan cuando borro/persisto el User correspondiente. Además, cuando insisto en un objeto News, quiero que persista el correspondiente User [pero que no se elimine si se borra el News]. Tengo un método de servicio que salva un objeto News de la siguiente manera:

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

session.save(n); 

Para el código anterior consigo la siguiente excepción:

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 

Cuál podría ser el problema aquí?

¿Soy incorrecto al tener un método de servicio que intenta salvar a un niño? ¿Debería siempre guardar al padre en su lugar?

Gracias.

ACTUALIZACIÓN: Si, en cambio, guardo al usuario como session.save(u) en lugar de las noticias, todo está bien. Entonces, la pregunta que queda es, ¿es incorrecto guardar al niño en lugar del padre? Si no, ¿cómo lo logro?

+0

¿Intentó ** session.save (u) ** en su lugar? – ManuPK

+1

@ManuPK Si uso 'session.save (u)' entonces todo está bien. Pregunto si es incorrecto si hago 'session.save (n)'? Si no es incorrecto, ¿cómo lo hago? –

Respuesta

6

que tiene que hacer things.These siguientes son las siguientes: - la opción de cascada

  • Quitar de lado de prensa.
  • En su caso de uso tiene una nueva noticia y un nuevo usuario. ¿Por qué usted desea persistir noticias. Persistir el objeto del usuario Ambos serán persistentes.
  • En otro caso de uso donde tiene usuario existente y desea agregar , una nueva noticia. En la implementación service/dao cree un método para persistir el objeto de noticias que pasa la identificación de usuario. Entonces puede usar cargar/obtener para asociar el uso y persistir la noticia
+0

Para responder explícitamente la pregunta del OP en el comentario: 'session.save (n)' es incorrecta. – Stewart

1

Creo que no es necesario establecer una cascada en el lado del niño. Basta con tener Cascade.ALL en el lado de los padres (User.news) debería ser suficiente.

Una cosa más, si va a eliminar noticias cuando el usuario es eliminado (como mencionó en su publicación), creo que necesita agregar el tipo de cascada Eliminar huérfano en el lado de los padres también.

Cuestiones relacionadas