英文:
How to add data to Many to Many association with extra column using JPA, Hibernate
问题
以下是翻译好的内容:
我有一个名为 User
的表和一个名为 Book
的表,我想要将它们连接起来。
因此,我创建了第三个名为 Borrow
的表,它具有外键 (book_id, user_id
),以及 takenDate
和 broughtDate
字段。
User.java
@Entity
@Table(name = "Users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
private String surname;
private String username;
private String email;
private String password;
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Borrow> borrow;
....
Book.java
@Entity
@Table(name = "Books")
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String title;
private String ISBN;
private String author;
private String issuer;
private Integer dateOfIssue;
private Boolean IsRented;
@OneToMany(mappedBy = "book", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Borrow> borrow;
.....
Borrow.java
@Entity
@Table(name = "Borrows")
@IdClass(BorrowId.class)
public class Borrow {
private Date takenDate;
private Date broughtDate;
@Id
@JsonIgnore
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "book_id", referencedColumnName = "id")
private Book book;
@Id
@JsonIgnore
@ManyToOne
@JoinColumn(name = "user_id", referencedColumnName = "id")
private User user;
....
BorrowId.java
public class BorrowId implements Serializable {
private int book;
private int user;
// getters/setters and most importantly equals() and hashCode()
public int getBook() {
return book;
}
public void setBook(int book) {
this.book = book;
}
public int getUser() {
return user;
}
public void setUser(int user) {
this.user = user;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof BorrowId)) return false;
BorrowId borrowId = (BorrowId) o;
return getBook() == borrowId.getBook() &&
getUser() == borrowId.getUser();
}
@Override
public int hashCode() {
return Objects.hash(getBook(), getUser());
}
}
我尝试像这样向 Borrow
表中添加数据:
@Transactional
@PostMapping("/addUser/{id}/borrow")
public ResponseEntity<Object> createItem(@PathVariable int id, @RequestBody Borrow borrow, @RequestBody Book book){
Optional<User> userOptional = userRepository.findById(id);
Optional<Book> bookOptional = bookRepository.findById(book.getId());
if(!userOptional.isPresent()){
throw new UserNotFoundException("id-" + id);
}
User user = userOptional.get();
borrow.setUser(user);
borrow.setBook(book);
borrowRepository.save(borrow);
URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").buildAndExpand(borrow.getId()).toUri();
return ResponseEntity.created(location).build();
}
我还没有完成它,因为我不确定如何操作 :/
欢迎任何提示!
英文:
I have a User
table and a Book
table that I would like to connect.
So I created third table Borrow
that has foreign key (book_id, user_id
) and takenDate
and broughtDate
fields.
User.java
@Entity
@Table(name = "Users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
private String surname;
private String username;
private String email;
private String password;
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Borrow> borrow;
....
Book.java
@Entity
@Table(name = "Books")
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String title;
private String ISBN;
private String author;
private String issuer;
private Integer dateOfIssue;
private Boolean IsRented;
@OneToMany(mappedBy = "book", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Borrow> borrow;
.....
Borrow.java
@Entity
@Table(name = "Borrows")
@IdClass(BorrowId.class)
public class Borrow {
private Date takenDate;
private Date broughtDate;
//lazy means it will get details of book
// only if we call GET method
@Id
@JsonIgnore
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "book_id", referencedColumnName = "id")
private Book book;
@Id
@JsonIgnore
@ManyToOne
@JoinColumn(name = "user_id", referencedColumnName = "id")
private User user;
....
BorowId.java
public class BorrowId implements Serializable {
private int book;
private int user;
// getters/setters and most importantly equals() and hashCode()
public int getBook() {
return book;
}
public void setBook(int book) {
this.book = book;
}
public int getUser() {
return user;
}
public void setUser(int user) {
this.user = user;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof BorrowId)) return false;
BorrowId borrowId = (BorrowId) o;
return getBook() == borrowId.getBook() &&
getUser() == borrowId.getUser();
}
@Override
public int hashCode() {
return Objects.hash(getBook(), getUser());
}
}
My MySql database design looks like this:
I am trying to add data to Borrow
table something like this:
EDITED
@Transactional
@PostMapping("/addUser/{id}/borrow")
public ResponseEntity<Object> createItem(@PathVariable int id, @RequestBody Borrow borrow, @RequestBody Book book){
Optional<User> userOptional = userRepository.findById(id);
Optional<Book> bookOptional = bookRepository.findById(book.getId());
if(!userOptional.isPresent()){
throw new UserNotFoundException("id-" + id);
}
User user = userOptional.get();
borrow.setUser(user);
borrow.setBook(book);
borrowRepository.save(borrow);
URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").buildAndExpand(borrow.getId()).toUri();
return ResponseEntity.created(location).build();
}
I have't finished it because I am not sure how :/
Any tip is appreciated!
答案1
得分: 0
你已经接近成功了。你只需要记住两件事:
1) 你还需要通过存储库获取Book
(目前只获取了User
)
2) 所有三个操作必须在同一个事务上下文中进行:
获取`User`,获取`Book`和保存`Borrow`实体。
提示:你可以将所有这些放在一个Service内,并将其标记为@Transactional
,或者将@Post
方法标记为@Transactional
。我建议第一种选项,但由你决定。
编辑:
Optional<Book> bookOptional = bookRepository.findById(book.getId());
此外,似乎在这里使用@EmbeddedId
而不是@IdClass
更合适,因为这些id实际上是外键实体:
@Embeddable
public class BorrowId {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "book_id", referencedColumnName = "id")
private Book book;
@ManyToOne
@JoinColumn(name = "user_id", referencedColumnName = "id")
private User user;
}
然后在Borrow
类中:
@Entity
class Borrow {
@EmbeddedId
BorrowId borrowId;
...
}
最后,在Post
方法中:
BorrowId borrowId = new BorrowId();
borrowId.setUser(user);
borrowId.setBook(book);
borrow.setBorrowId(borrowId);
borrowRepository.save(borrow);
英文:
You are almost there. You just have to keep in mind two things:
1) You have to fetch the Book
via repository as well (you only fetch the User
currently)
2) All three operation have to be within the same transactional context:
fetching of `User`, fetching of `Book` and save `Borrow` entity.
TIP: You can put all these inside a Service and mark it as @Transactional
or mark the @Post
method as @Transactional
. I would suggest first option, but it is up to you.
EDIT:
Optional<Book> bookOptional = bookRepository.findById(book.getId());
Also, it seems adequate to use @EmbeddedId
instead of @IdClass
here as ids are actual foreign entities:
@Embeddable
public class BorrowId{
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "book_id", referencedColumnName = "id")
private Book book;
@ManyToOne
@JoinColumn(name = "user_id", referencedColumnName = "id")
private User user;
}
and then in the Borrow class:
@Entity class Borrow{
@EmbeddedId BorrwId borrowId;
...
}
and in the Post method:
BorrowId borrowId = new BorrowId();
borrowId.setUser(user);
borrowId.setBook(book);
borrow.setBorrowId(borrowId);
borrowRepository.save(borrow);
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论