Spring Data Rest / JPA级联在补丁上持续存在

时间:2018-04-03 13:25:21

标签: java jpa spring-data-rest

我有两个实体BookBookEvent。它们由ManyToOne-Relationship链接,即一本书可以有许多BookEvents。 我将Book视为聚合根,并为Book实体设置了一个Repository,但没有为BookEvent设置。

@Entity
@Table(name = "book")
public class Book {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String title;

    @OneToMany(mappedBy = "book", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<BookEvent> events = new ArrayList<>();


    public List<BookEvent> getEvents() {
        return events;
    }

    public void setEvents(List<BookEvent> events) {
        for (BookEvent event: events) {
            event.setBook(this);
        }
        this.events = events;
    }

    public void addEvent(BookEvent event) {
        events.add(event);
        event.setBook(this);
    }

    public void removeEvent(BookEvent event) {
        events.remove(event);
        event.setBook(null);
    }
}

(这里省略了其他的getter / setter)。

@Entity
public class BookEvent {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @ManyToOne
    @JoinColumn(name="book_id")
    private Book book;
    private LocalDate date;


    @PreRemove
    private void removeEventFromBook(){
        book.removeEvent(this);
    }

    public Book getBook() {
        return book;
    }

    public void setBook(Book book) {
        this.book = book;
        if (!this.book.getEvents().contains(this)) {
            this.book.getEvents().add(this);
        }
    }
}

我现在想在创建本书后向书中添加一个新事件。我使用Spring Data Rest。

使用POST和一个事件创建图书可以正常工作:

{
    "title": "My example book",
    "events": [ 
        {
            "type": "BOUGHT",
            "date": "2017-05-09"
        }
        ]
}

给出答案:

{
    "title": "My example book",
    "events": [
        {
            "id": 3,
            "date": "2017-05-09",
            "_links": {
                "book": {
                    "href": "http://localhost:8080/api/books/2"
                }
            }
        }
    ]
}

但是,如果我然后执行JSON补丁附加一个新事件,该事件将包含在对PATCH请求的响应中,但它实际上并未保存在数据库中(之后的书上的GET不会返回事件当数据库的列book_id为空时。)

[
    {
    "op": "add",
    "path": "/events/-",
    "value": 
        {
            "date": "2017-05-09"
        }
}
]

使用调试器时,在初始POST请求中调用setEvents()方法,但在PATCH请求期间,仅调用getEvents()方法 - no setBook()或{{1 }} 方法。我认为存在问题。

我的实体设置有问题吗?

1 个答案:

答案 0 :(得分:1)

问题是我的设置是没有连接表的双向OneToMany设置。问题可以通过两种方式解决:

  • 创建连接表。这是通过向Book类的events属性添加- "5432:5432" 注释来完成的。这需要在数据库中添加一个表,因此我没有选择这种方式。
  • 使用单向OneToMany设置(请参阅Java Persistence/OneToMany)。这仅受JPA 2.x支持,但这在Spring Boot 2.0设置中没有问题。这种实现看起来很干净。

我的代码现在看起来如下:

@JoinTable

没有必要更新互惠链接的特殊getter / setter。这将获得带有SDR的干净JSON响应,而每个事件都没有@Entity @Table(name = "book") public class Book { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @OneToMany(cascade = ALL) //The cascade is important as otherwise a new event won't be saved. @JoinColumn(name="book_id", referencedColumnName = "id") private List<BookEvent> events = new ArrayList<>(); //Standard getter and setter for getEvents() and setEvents() } @Entity public class BookEvent { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private long id; @Column(name="book_id") private Long bookId; //No getter/setter for bookId was necessary } 属性。添加和删​​除新条目也很有效。