programing

Spring Data REST 및 JPA를 사용하여 양방향 관계를 유지하는 방법은 무엇입니까?

newnotes 2023. 3. 1. 11:30
반응형

Spring Data REST 및 JPA를 사용하여 양방향 관계를 유지하는 방법은 무엇입니까?

REST 시 Spring Data REST가 있는 OneToMany ★★★★★★★★★★★★★★★★★」ManyToOne관계에서는 PUT 조작은 "소유하지 않는" 엔티티에 200을 반환하지만 실제로는 가입된 리소스를 유지하지는 않습니다.

엔티티 예:

@Entity(name = 'author')
@ToString
class AuthorEntity implements Author {

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

    String fullName

    @ManyToMany(mappedBy = 'authors')
    Set<BookEntity> books
}


@Entity(name = 'book')
@EqualsAndHashCode
class BookEntity implements Book {

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

    @Column(nullable = false)
    String title

    @Column(nullable = false)
    String isbn

    @Column(nullable = false)
    String publisher

    @ManyToMany(fetch = FetchType.LAZY, cascade = [CascadeType.ALL])
    Set<AuthorEntity> authors
}

「 」로 는,PagingAndSortingRepository , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , .Book을.authors링크하여 관련짓는 작성자의 URI를 사용하여 PUT을 수행합니다.이데올로기 때문에

하고 Author로 books링크 응답은 200을 반환하지만 관계는 유지되지 않습니다.

이게 예상된 동작인가요?

dr;dr

중요한 것은 Spring Data REST가 아니라 시나리오에서 쉽게 작동하도록 하는 것입니다. 그러나 모델이 연결의 양끝을 동기화하도록 하는 것입니다.

문제

볼 수 있는 으로 Spring 가 Spring Data REST를 합니다.books AuthorEntity이에 .authors의 of의 BookEntitySpring Data REST는 JPA를 사용합니다.수동으로 설정기를 호출하고 결과를 유지하려고 하는 것만으로 잘못된 동작을 재현할 수 있습니다.

어떻게 해결할까요?

쌍방향 어소시에이션을 삭제할 수 없는 경우(아래를 참조해 주세요)는, 어소시에이션의 변경이 양쪽 모두에 반영되도록 하는 것 뿐입니다. 이 는 '를 ''에 요.BookEntity「 」 「 」 :

class AuthorEntity {

  void add(BookEntity book) {

    this.books.add(book);

    if (!book.getAuthors().contains(this)) {
       book.add(this);
    }
  }
}

경우 BookEntity상대측으로부터의 변경도 확실히 반영하고 싶은 경우에서도 마찬가지입니다.if기본적으로 필수입니다.그렇지 않으면 두 가지 방법이 항상 자신을 호출합니다.

Spring Data REST는 기본적으로 필드 액세스를 사용하기 때문에 실제로 이 로직을 투입할 수 있는 메서드는 없습니다.하나의 옵션은 속성 액세스로 전환하여 로직을 설정기에 넣는 것입니다. 다른 으로는 '보다 낫다'라는 주석이 도 있습니다.@PreUpdate/@PrePersist엔티티에 반복하여 변경 내용이 양쪽에 반영되도록 합니다.

문제의 근본 원인 제거

보시는 바와 같이 도메인 모델은 매우 복잡합니다.어제 트위터에서 농담한 것처럼:

쌍방향 어소시에이션 규칙 #1: 사용하지 말 것...:)

가능한 한 쌍방향 관계를 사용하지 않고 저장소로 폴백하여 연결의 배면을 구성하는 모든 엔티티를 얻으면 일반적으로 문제가 단순해집니다.

어느 쪽을 잘라낼지 결정하기 위한 좋은 휴리스틱스는 어느 쪽이 정말 핵심이고 모델링할 도메인에 중요한지를 생각하는 것입니다.당신의 경우, 작가가 책을 쓰지 않고 존재해도 전혀 문제가 없다고 생각합니다.반대로, 저자가 없는 책은 전혀 말이 되지 않는다.그래서 저는 이 노래를authors합니다.BookEntity 이 방법에서는 하겠습니다.BookRepository:

interface BookRepository extends Repository<Book, Long> {

  List<Book> findByAuthor(Author author);
}

이 이전에 " " " " " " " " " " " " " " " " " 를 호출할 수 있는 합니다.author.getBooks()이제 저장소로 작업할 수 있습니다.그러나 긍정적인 측면에서는 도메인 오브젝트에서 모든 문제를 제거하고 그 과정에서 책과 저자에 대한 명확한 의존 방향을 만들어 냈습니다.책은 작가에게 의존하지만 그 반대는 아니다.

REST api를 통해 POJO(양방향 매핑@OneToMany 및 @ManyToOne 포함)를 JSON으로 송신할 때 데이터는 부모 엔티티와 자녀 엔티티에 모두 유지되지만 외부 키 관계가 확립되지 않았습니다.이는 양방향 어소시에이션을 수동으로 유지해야 하기 때문에 발생합니다.

에는 JPA라는 .@PrePersist이는 엔티티가 지속되기 전에 해당 엔티티에 주석이 달린 메서드가 실행되도록 하기 위해 사용할 수 있습니다.그자 엔티티를 삽입하기 에 JPA로 을 단 @PrePersist하위 엔티티 목록을 반복하고 상위 엔티티를 수동으로 설정합니다.

당신의 경우 다음과 같습니다.

class AuthorEntitiy {
    @PrePersist
    public void populateBooks {
        for(BookEntity book : books)
            book.addToAuthorList(this);   
    }
}

class BookEntity {
    @PrePersist
    public void populateAuthors {
        for(AuthorEntity author : authors)
            author.addToBookList(this);   
    }
}

후 오류가 할 수 에 "재귀 오류"로 을 붙이지 않도록 .이 오류를 피하기 위해 부모 클래스는@JsonManagedReference그리고 당신의 자녀는@JsonBackReference이 솔루션은 나에게 효과가 있었습니다.당신에게도 효과가 있기를 바랍니다.

이 링크에는 재귀 문제를 탐색하는 방법에 대한 매우 좋은 튜토리얼이 있습니다.쌍방향 관계

@JsonManagedReference와 @JsonBackReference를 사용할 수 있어 매우 효과가 있었습니다.

@BeforeLinkSave 핸들러를 추가하여 엔티티 간의 양방향 관계를 상호 링크함으로써 @RepositoryEventHandler를 이용할 수도 있다고 생각합니다.이건 나한테 효과가 있는 것 같아.

@Component
@RepositoryEventHandler
public class BiDirectionalLinkHandler {

    @HandleBeforeLinkSave
    public void crossLink(Author author, Collection<Books> books) {
        for (Book b : books) {
            b.setAuthor(author);
        }
    }
}

주의: @HandlBeforeLinkSave는 첫 번째 파라미터에 따라 호출됩니다.Author 클래스에 대응하는 여러 관계가 있는 경우 두 번째 파라미터는 Object여야 하며 메서드 내에서 다른 관계 유형을 테스트해야 합니다.

언급URL : https://stackoverflow.com/questions/30464782/how-to-maintain-bi-directional-relationships-with-spring-data-rest-and-jpa

반응형