在 spring 引导 JPA 中,如何正确地 POST 实体表示具有外键关联到不同实体的对象?
In spring boot JPA, how to properly POST an object whose entity representation has a foreign key association to a different entity?
如果我有一个实体包含另一个 class 的对象,例如一个 Book
实体,其中有一个 Publisher
实体,关联如下:
@ManyToOne
@JoinColumn(name="PUB_CODE", referencedColumnName = "PUB_CODE")
private Publisher pub;
这是secure/correct(我在这个例子中看到数据库中的正确数据,但不是 100% 确定它是否适用于所有情况)方法 post 具有数据库中的外键关联?我不知道这样做在事务原子性或线程方面是否安全,或者它是否有效。相关代码如下:
Book.java
package app.domain;
/*imports*/
@Entity
public class Book implements Serializable{
/**
*
*/
private static final long serialVersionUID = -6902184723423514234L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
@Column(nullable = false, unique=true)
private String bookName;
@Column(nullable = false)
private int pageCount;
@ManyToOne
@JoinColumn(name="PUB_CODE", referencedColumnName="PUB_CODE")
private Publisher pub;
/*public getters and setters*/
}
Publisher.java
package app.domain;
/*imports*/
@Entity
public class Publisher implements Serializable {
private static final long serialVersionUID = 4750079787174869458L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
@Column(name="PUB_CODE",nullable = false, unique = true)
private String publisherCode;
@Column(nullable = false)
private String publisherName;
/*public getters and setters*/
}
BookRepo.java
package app.service;
/*imports*/
public interface BookRepo extends JpaRepository<Book, Long>{
@Query("SELECT pb FROM Publisher pb WHERE pb.publisherCode = TRIM(UPPER(:pubCode))")
public Publisher findPublisherByPubCode(@Param("pubCode")String pubCode);
}
BookController.java
package app.controller;
/*imports*/
@RestController
@RequestMapping(value = "/books")
public class BookController {
private BookRepo bookRepo;
@Autowired
public BookController(BookRepo bookRepo) {
this.bookRepo = bookRepo;
}
//The ApiPathParam is for JSONDOC purposes
@RequestMapping(value = "/create", method = RequestMethod.POST)
public List<Book> create(@ApiPathParam(name = "book") @RequestBody Book book, @ApiPathParam(name = "pubCode") @RequestParam("pubCode") String pubCode) {
// Assume exception handling
Publisher pbToAttachToThisBook = bookRepo.findPublisherByPubCode(pubCode);
book.setPub(pbToAttachToThisBook);
bookRepo.save(book);
return bookRepo.findAll();
}
}
Post对象体(输入POST工具):
{
"bookName": "goosebumps",
"id": 0,
"pageCount": 332,
"pub": {
"id": 0,
"publisherCode": "",
"publisherName": "",
"serialVersionUID": 0
},
"serialVersionUID": 0
}
提供的 pubCode 参数输入,也进入 POST 工具,在与上述相同的调用中 : 'SC'
以上代码执行后,在Booktable中,出现了上面这本书的条目,其PUB_CODE
外键列填入'SC'
,并且调用的POST控制器方法返回的List<Book>
显示新添加的图书包含Publisher
实体信息(如全名"Scholastic"),出版商为PUB_CODE='SC'
已经存在于数据库中。
谢谢。
听起来您需要从 Rest Resources/ API specs
到 separate/decouple
您的 data layer's domain model
,因为它们可能会以不同的速度发展。此外,您对 JPA
的选择不应影响 API specs
.
如果你觉得这是你想要追求的东西,那里有很多资源,包括 Best Practices for Better RESTful API
您最初发布的技术(传递 FK ID,在您的控制器中手动检索它,并在实体上明确设置)是有效且安全的。
我不知道有什么更简洁的方法,除非您转向 HATEOAS 主体,它允许资源 link 处理:http://projects.spring.io/spring-hateoas/
如果我有一个实体包含另一个 class 的对象,例如一个 Book
实体,其中有一个 Publisher
实体,关联如下:
@ManyToOne
@JoinColumn(name="PUB_CODE", referencedColumnName = "PUB_CODE")
private Publisher pub;
这是secure/correct(我在这个例子中看到数据库中的正确数据,但不是 100% 确定它是否适用于所有情况)方法 post 具有数据库中的外键关联?我不知道这样做在事务原子性或线程方面是否安全,或者它是否有效。相关代码如下:
Book.java
package app.domain;
/*imports*/
@Entity
public class Book implements Serializable{
/**
*
*/
private static final long serialVersionUID = -6902184723423514234L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
@Column(nullable = false, unique=true)
private String bookName;
@Column(nullable = false)
private int pageCount;
@ManyToOne
@JoinColumn(name="PUB_CODE", referencedColumnName="PUB_CODE")
private Publisher pub;
/*public getters and setters*/
}
Publisher.java
package app.domain;
/*imports*/
@Entity
public class Publisher implements Serializable {
private static final long serialVersionUID = 4750079787174869458L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
@Column(name="PUB_CODE",nullable = false, unique = true)
private String publisherCode;
@Column(nullable = false)
private String publisherName;
/*public getters and setters*/
}
BookRepo.java
package app.service;
/*imports*/
public interface BookRepo extends JpaRepository<Book, Long>{
@Query("SELECT pb FROM Publisher pb WHERE pb.publisherCode = TRIM(UPPER(:pubCode))")
public Publisher findPublisherByPubCode(@Param("pubCode")String pubCode);
}
BookController.java
package app.controller;
/*imports*/
@RestController
@RequestMapping(value = "/books")
public class BookController {
private BookRepo bookRepo;
@Autowired
public BookController(BookRepo bookRepo) {
this.bookRepo = bookRepo;
}
//The ApiPathParam is for JSONDOC purposes
@RequestMapping(value = "/create", method = RequestMethod.POST)
public List<Book> create(@ApiPathParam(name = "book") @RequestBody Book book, @ApiPathParam(name = "pubCode") @RequestParam("pubCode") String pubCode) {
// Assume exception handling
Publisher pbToAttachToThisBook = bookRepo.findPublisherByPubCode(pubCode);
book.setPub(pbToAttachToThisBook);
bookRepo.save(book);
return bookRepo.findAll();
}
}
Post对象体(输入POST工具):
{
"bookName": "goosebumps",
"id": 0,
"pageCount": 332,
"pub": {
"id": 0,
"publisherCode": "",
"publisherName": "",
"serialVersionUID": 0
},
"serialVersionUID": 0
}
提供的 pubCode 参数输入,也进入 POST 工具,在与上述相同的调用中 : 'SC'
以上代码执行后,在Booktable中,出现了上面这本书的条目,其PUB_CODE
外键列填入'SC'
,并且调用的POST控制器方法返回的List<Book>
显示新添加的图书包含Publisher
实体信息(如全名"Scholastic"),出版商为PUB_CODE='SC'
已经存在于数据库中。
谢谢。
听起来您需要从 Rest Resources/ API specs
到 separate/decouple
您的 data layer's domain model
,因为它们可能会以不同的速度发展。此外,您对 JPA
的选择不应影响 API specs
.
如果你觉得这是你想要追求的东西,那里有很多资源,包括 Best Practices for Better RESTful API
您最初发布的技术(传递 FK ID,在您的控制器中手动检索它,并在实体上明确设置)是有效且安全的。
我不知道有什么更简洁的方法,除非您转向 HATEOAS 主体,它允许资源 link 处理:http://projects.spring.io/spring-hateoas/