2011-11-22 18 views
6

Tôi có một mối quan hệ cha-con:Hibernate: Lưu Chánh tự động trước khi lưu Child

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

Đây User là phụ huynh và News là đứa trẻ. Lý do mà tôi có các hoạt động xếp tầng như vậy là vì tôi muốn tất cả các đối tượng News bị xóa/tiếp tục tồn tại khi tôi xóa/duy trì User tương ứng. Ngoài ra khi tôi vẫn còn một đối tượng News tôi muốn tương ứng User để được duy trì [nhưng không bị xóa nếu News bị xóa]. Tôi có một phương pháp dịch vụ tiết kiệm một đối tượng News như sau:

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

session.save(n); 

Đối với các mã trên tôi nhận được ngoại lệ sau đây:

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 

Điều gì có thể vấn đề ở đây?

Tôi có sai khi có phương pháp dịch vụ cố gắng cứu đứa trẻ không? Tôi có nên luôn luôn lưu phụ huynh thay thế không?

Cảm ơn.

CẬP NHẬT: Nếu thay vào đó, hãy lưu người dùng dưới dạng session.save(u) thay vì tin tức, mọi thứ đều ổn. Vì vậy, câu hỏi vẫn còn là, nó là không chính xác để lưu các con thay vì cha mẹ? Nếu không, thì làm thế nào để đạt được nó?

+0

bạn đã thử ** session.save (u) ** thay thế? – ManuPK

+1

@ManuPK Nếu tôi sử dụng 'session.save (u)' thì mọi thứ đều ổn. Tôi hỏi là nó không chính xác nếu tôi làm 'session.save (n)'? Nếu nó không đúng, thì làm sao tôi làm được? –

Trả lời

6

Bạn phải làm things.These sau: - Tùy chọn cascade

  • Remove từ phía tin tức.
  • Trong trường hợp sử dụng của bạn, bạn có mục tin tức mới và người dùng mới. Tại sao bạn muốn duy trì mục tin tức. Đối tượng người dùng Persist. Cả hai sẽ được duy trì.
  • Trong trường hợp sử dụng khác mà bạn có người dùng hiện tại và bạn muốn thêm một mục tin tức mới. Trong việc thực hiện dịch vụ/dao tạo ra một phương thức để duy trì đối tượng tin tức chuyển id người dùng. Sau đó, bạn có thể sử dụng tải/nhận để kết hợp việc sử dụng và duy trì mục tin tức
+0

Vì vậy, để trả lời rõ ràng câu hỏi của OP trong nhận xét: 'session.save (n)' là không chính xác. – Stewart

1

Tôi tin rằng bạn không cần đặt thác ở bên con. Đơn giản chỉ cần có Cascade.ALL trên phía cha mẹ (User.news) là đủ.

Một điều nữa, nếu bạn định xóa tin tức khi người dùng bị xóa (như bạn đã đề cập trong bài đăng của bạn), tôi tin rằng bạn cần phải thêm loại thác Xóa trẻ mồ côi ở bên mẹ.

Các vấn đề liên quan