2016-03-15 74 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