如何在Spring Data Rest中的两个实体之间POST和PUT关系@OneToMany / @ManyToOne?

时间:2016-05-27 15:47:55

标签: spring-boot spring-data-jpa spring-data-rest

我有一个简单的Spring Boot应用程序用于Spring Data Rest实现。

这是主要课程:

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

我有两个简单的实体:书和作者。 彼此之间的关系是1作者 - > N书

这是Author.class:

@Entity
@Table
public class Author {

    @Id
    @GeneratedValue(generator = "uuid")
    @GenericGenerator(name = "uuid", strategy = "uuid2")
    @Column(columnDefinition = "BINARY(16)", length = 16)
    private UUID id;

    @Column
    private String name;

    @OneToMany(fetch = FetchType.LAZY, targetEntity = Book.class, mappedBy = "author")
    private List<Book> books;

    // getters and setters

}

这是Book.class:

@Entity
@Table
public class Book {

    @Id
    @GeneratedValue(generator = "uuid")
    @GenericGenerator(name = "uuid", strategy = "uuid2")
    @Column(columnDefinition = "BINARY(16)", length = 16)
    private UUID id;

    @Column
    private String title;

    @Column
    private String language;

    @ManyToOne(fetch = FetchType.EAGER, targetEntity = Author.class)
    private Author author;

    // getters and setters

}

这是&#34; AuthorRepository&#34;:

@RestResource(path = "authors", rel = "authors")
public interface AuthorRepository extends JpaRepository<Author, UUID> {
}

这是&#34; BookRepository&#34;:

@RestResource(path = "books", rel = "books")
public interface BookRepository extends JpaRepository<Book, UUID> {
}

应用程序运行完美,在网址http://localhost:8080/我有此回复页面:

{
  "_links" : {
    "authors" : {
      "href" : "http://localhost:8080/authors{?page,size,sort}",
      "templated" : true
    },
    "books" : {
      "href" : "http://localhost:8080/books{?page,size,sort}",
      "templated" : true
    },
    "profile" : {
      "href" : "http://localhost:8080/profile"
    }
  }
}

网址http://localhost:8080/authors会返回此页面:

{
  "_embedded" : {
    "authors" : [ ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/authors"
    },
    "profile" : {
      "href" : "http://localhost:8080/profile/authors"
    }
  },
  "page" : {
    "size" : 20,
    "totalElements" : 0,
    "totalPages" : 0,
    "number" : 0
  }
}

网址http://localhost:8080/books返回此页面:

{
  "_embedded" : {
    "books" : [ ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/books"
    },
    "profile" : {
      "href" : "http://localhost:8080/profile/books"
    }
  },
  "page" : {
    "size" : 20,
    "totalElements" : 0,
    "totalPages" : 0,
    "number" : 0
  }
}

我试图通过Book类开始一些HTTP POST。

HTTP POST
url: http://localhost:8080/books
header: Content-Type:application/json
payload: { "title": "Book Title" }

Status: 201: Created
Location: http://localhost:8080/books/61311c9b-b33a-463c-9e6e-8e5efc0a7ad1

实际上,网址http://localhost:8080/books/61311c9b-b33a-463c-9e6e-8e5efc0a7ad1会返回此页面:

{
  "title" : "Book Title",
  "language" : null,
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/books/61311c9b-b33a-463c-9e6e-8e5efc0a7ad1"
    },
    "book" : {
      "href" : "http://localhost:8080/books/61311c9b-b33a-463c-9e6e-8e5efc0a7ad1"
    },
    "author" : {
      "href" : "http://localhost:8080/books/61311c9b-b33a-463c-9e6e-8e5efc0a7ad1/author"
    }
  }
}

我为作者做了同样的事情。

HTTP POST
url: http://localhost:8080/authors
header: Content-Type:application/json
payload: { "name": "Author Name" }

Status: 201: Created
Location: http://localhost:8080/authors/634d3bd8-abe6-472b-97cd-04a455bdfb11

这是该网址的响应页面:

{
  "name" : "Author Name",
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/authors/634d3bd8-abe6-472b-97cd-04a455bdfb11"
    },
    "author" : {
      "href" : "http://localhost:8080/authors/634d3bd8-abe6-472b-97cd-04a455bdfb11"
    },
    "books" : {
      "href" : "http://localhost:8080/authors/634d3bd8-abe6-472b-97cd-04a455bdfb11/books"
    }
  }
}

请注意,作者和书籍之间的关系尚不存在,因此我尝试发送PUT请求。

HTTP PUT
url: http://localhost:8080/authors/634d3bd8-abe6-472b-97cd-04a455bdfb11
header: Content-Type:application/json
payload: { "books": ["http://localhost:8080/books/61311c9b-b33a-463c-9e6e-8e5efc0a7ad1"] }

Status: 204: No Content
Location: http://localhost:8080/authors/634d3bd8-abe6-472b-97cd-04a455bdfb11

我的响应代码是HTTP 204(无内容)。 如果我转到网址http://localhost:8080/authors/634d3bd8-abe6-472b-97cd-04a455bdfb11/books我会期待这本书,但我有这个结果:

{
  "_embedded" : {
    "books" : [ ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/authors/634d3bd8-abe6-472b-97cd-04a455bdfb11/books"
    }
  }
}

&#34;书籍&#34;财产仍然是空的。为什么呢?

此外,此网址返回空白页面:http://localhost:8080/books/61311c9b-b33a-463c-9e6e-8e5efc0a7ad1/author

该关系尚未按我的预期处理。

如果我在插入书籍之前从作者开始进行相同的处理,则存在关系。

如何从Book实体开始保存两个实体之间的关系?

由于

2 个答案:

答案 0 :(得分:0)

为了使这种情况发生逆转,你的@OneToMany(fetch = FetchType.LAZY,targetEntity = Book.class,mappedBy =&#34; author&#34;)中应该有级联选项来实际保留书中的更改实体。

试试这个:

@OneToMany(fetch = FetchType.LAZY,targetEntity = Book.class,mappedBy =&#34; author&#34;,cascade = CascadeType.ALL)

答案 1 :(得分:0)

您正在使用双向 OneToMany ,因此您必须使用“实用程序方法”,无论何时添加或删除子元素,都会同步两端(请参阅manual )。

但你可以做几乎相同的修改books setter,就像这样:

@Entity
public class Author {

    //...

    @OneToMany(mappedBy = "author")
    private List<Book> books;

    public void setBooks(List<Book> books) {
        books.forEach(book -> book.setAuthor(this));
        this.books = books;
    }


    //...
}

查看我的example

P.S。如果您的实体是独立的,请不要使用cascade = CascadeType.ALL,而是使用cascade = {CascadeType.PERSIST, CascadeType.MERGE}(或根本不使用级联)。