2016-03-15 69 views
0

我想在我自己的項目中使用H2數據庫複製休眠示例from here - 使用H2數據庫 - 使用Flyway遷移初始化 - 以及Spring Data。問題是,當我保存父對象BookCategory時,它還保存了孩子(Book對象),但它不保存book_category_id,即「孩子」對象的「父母ID」!休眠不爲OneToMany兒童保存父母ID

我的SQL是這樣的:

CREATE SEQUENCE SEQ_IDNUMS START WITH 1; 

CREATE TABLE book_category (
    id int(11) NOT NULL, 
    name varchar(255) NOT NULL, 
    PRIMARY KEY (id,name) 
); 

CREATE TABLE book (
    id int(11) NOT NULL, 
    name varchar(255) DEFAULT NULL, 
    book_category_id int(11) DEFAULT NULL 
); 
alter table book add constraint pk_book_id PRIMARY KEY (id); 
alter table book add constraint fk_book_bookcategoryid FOREIGN KEY(book_category_id) REFERENCES book_category(id) ON DELETE CASCADE; 

然後,我的書類:

import javax.persistence.*; 

@Entity 
public class Book{ 
    private int id; 
    private String name; 
    private BookCategory bookCategory; 

    public Book() { } 

    public Book(String name) { this.name = name; } 

    @Id 
    @SequenceGenerator(name = "seq_idnums", sequenceName = "seq_idnums", allocationSize = 1) 
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_idnums") 
    public int getId() { return id; } 

    public void setId(int id) { this.id = id; } 

    public String getName() { return name; } 

    public void setName(String name) { this.name = name; } 

    @ManyToOne 
    @JoinColumn(name = "book_category_id") 
    public BookCategory getBookCategory() { return bookCategory; } 

    public void setBookCategory(BookCategory bookCategory) { this.bookCategory = bookCategory; } 
} 

而且我BookCategory類:

import java.util.Set; 

import javax.persistence.*; 

@Entity 
@Table(name = "book_category") 
public class BookCategory { 
    private int id; 
    private String name; 
    private Set<Book> books; 

    public BookCategory(){ } 

    public BookCategory(String name, Set<Book> books) { 
    this.name = name; 
    this.books = books; 
    } 

    @Id 
    @SequenceGenerator(name = "seq_idnums", sequenceName = "seq_idnums", allocationSize = 1) 
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_idnums") 
    public int getId() { return id; } 

    public void setId(int id) { this.id = id; } 

    public String getName() { return name; } 

    public void setName(String name) { this.name = name; } 

    @OneToMany(mappedBy = "bookCategory", cascade = CascadeType.ALL) 
    public Set<Book> getBooks() { return books; } 

    public void setBooks(Set<Book> books) { this.books = books; }  
} 

至於儲蓄的一部分,我m完全按照示例進行:

BookCategory categoryA = new BookCategory("Category A", new HashSet<Book>(){{ 
    add(new Book("Book A1")); 
    add(new Book("Book A2")); 
    add(new Book("Book A3")); 
}}); 

BookCategory categoryB = new BookCategory("Category B", new HashSet<Book>(){{ 
    add(new Book("Book B1")); 
    add(new Book("Book B2")); 
    add(new Book("Book B3")); 
}}); 

bookCategoryRepository.save(new HashSet<BookCategory>() {{ 
    add(categoryA); 
    add(categoryB); 
}}); 

最後,我BookCategoryRepository看上去只有這樣,由於春季數據法寶:

import org.springframework.data.repository.CrudRepository; 

public interface BookCategoryRepository extends CrudRepository<BookCategory, Long> { 
} 

這個問題已經被問了幾次,如here。在那裏,接受的答案基本上說,與@JoinColumn一側是應該堅持的一面。正如你在上面的代碼中看到的那樣,我正在複製的例子並沒有這樣做,而是堅持了另一方,而且這對於作者來說顯然工作得很好。如果我會盡力堅持書對象,而不是,我得到這個異常:

[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : Book.bookCategory -> BookCategory; nested exception is java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : Book.bookCategory -> BookCategory] with root cause org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : Book.bookCategory -> BookCategory

......所以這不是解決辦法。

現在,另一個問題here及其答案表明問題是id列必須爲空。然而,這導致遷飛路線錯誤,那麼,我真的不希望有我的ID字段可爲空反正:

Invocation of init method failed; nested exception is org.flywaydb.core.internal.dbsupport.FlywaySqlScriptException: Error executing statement at line 14: alter table book add constraint pk_book_id PRIMARY KEY (id)

另一個問題here認爲,「nullable = false」必須拆除,但首先我沒有這個。

我完全處於虧損狀態。什麼可能有錯誤,以及如何解決它?

+0

您正在創建一本新書'新書(「書A1」)',但您不在此新書對象中設置'bookCategory'字段。你可以設置該字段並嘗試。另一方面,我通常會將實體傳遞給'repository'上的'save'方法。從來沒有嘗試像你一樣傳遞一個HashSet像bookCategoryRepository.save(new HashSet ()'。這是否工作? –

回答

1

使用您當前的映射@ManyToOne是所有者,但在創建新書對象時使用new Book("Book A1"),但未在此新書對象中設置bookCategory字段(所有者)。

你可以設置該字段並嘗試保存。

使用以下代碼進行測試,並且可以直接使用session.save(categoryA)而不是repository進行保存。但這應該沒有什麼不同。

BookCategory categoryA = new BookCategory("Category A"); 
categoryA.setBooks(new HashSet<Book>(){{ 
        add(new Book("Book A1", categoryA)); 
        add(new Book("Book A2", categoryA)); 
        add(new Book("Book A3", categoryA)); 
       }}); 

正如你可能已經猜到了,設定bookCategory場我添加了一個新的構造函數,如下班,以保持它的簡單。你也可以使用setters。

public BookCategory(String name) { 
     this.name = name; 
     } 

    public Book(String name, BookCategory category) { 
     this.name = name; 
     this.bookCategory = category; 
    } 
+0

那麼,你知道什麼嗎?那麼工作!我然後嘗試應用你剛剛對我的實際問題做了什麼(這個例子是我經歷過的一件簡單的事情),但發現我已經在做這件事了,然後我從書籍和書目類庫開始慢慢地重新構建自定義的DTO ......我不知道發生了什麼,但現在它工作......我不知道它是否做了任何事情,但我原來的DTO類被稱爲「項目」和「ItemData」(表「項目」和「item_data」)。現在我有「項目」和「ItemData」(「item」和「item_data」),它的工作原理...無論如何,謝謝你真是太棒了! – ZeroOne

+0

@ZeroOne很高興知道它正在工作。 –

0

我相信你的問題是保存操作不是從Book級聯到BookCategory。 BookCategory是一個未保存的瞬態實例,因此您必須在保存書籍之前明確地保存它,或者將Book級聯選項添加到Book。

試試這個:

@ManyToMany(cascade=CascadeType.ALL) 
@JoinColumn(name = "book_category_id") 
public BookCategory getBookCategory() { return bookCategory; } 

編輯:我想我誤解了問題。在那個筆記上:你的複製粘貼不包括你的測試方法的開始;你是否像最初的例子那樣使用@Transactional方法?看起來你已經遵循了這封信,一切都應該起作用。

+0

'@ ManyToMany'不正確 –

+0

我的測試方法實際上沒有用@ Transactional註釋,因爲我相信Spring Data應該爲我處理這個問題嗎?無論如何,我嘗試添加註釋,但沒有任何改變。:( – ZeroOne