【问题标题】:Spring Data Rest/JPA cascade persist on patchSpring Data Rest/JPA 级联在补丁上持续存在
【发布时间】:2018-09-12 20:24:55
【问题描述】:

我有两个实体,BookBookEvent。它们通过多对一关系链接,即一本书可以有许多 BookEvents。 我将 Book 视为聚合根,并为 Book 实体提供一个存储库,但对 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 以追加一个新事件,则该事件包含在对 PATCH 请求的响应中,但它实际上并没有保存在数据库中(之后书上的 GET 不会返回该事件并且当数据库的 book_id 列为空时)。

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

使用调试器时,在初始 POST 请求时调用 setEvents() 方法,但在 PATCH 请求期间,仅调用 getEvents() 方法 - 没有 setBook()addEvent() 方法。我认为问题就在那里。

我的实体设置有问题吗?

【问题讨论】:

    标签: java jpa spring-data-rest


    【解决方案1】:

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

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

    我的代码现在如下所示:

    @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
    }
    

    不需要更新互惠链接的特殊 getter/setter。这将获得带有 SDR 的干净 JSON 响应,每个事件都没有 _links 属性。添加和删​​除新条目也可以。

    【讨论】:

    • 伙计,我已经完成了与您类似的所有操作,但是在保留子实体时出现错误 - 它没有获得父实体的 id
    猜你喜欢
    • 1970-01-01
    • 2017-03-30
    • 2015-07-14
    • 1970-01-01
    • 2013-03-05
    • 1970-01-01
    • 1970-01-01
    • 2013-09-17
    • 1970-01-01
    相关资源
    最近更新 更多