2015-05-26 9 views
13

Yay Veri REST ile çalışma. Bir oneToMany veya ManyToOne ilişkisine sahipseniz, PUT işlemi "sahip olmayan" varlık üzerinde 200 değerini döndürür, ancak birleştirilmiş kaynağı gerçekten sürdürmez.Yay Veri REST ve JPA ile çift yönlü ilişkiler nasıl korunur?

Örnek Varlıklar. Eğer bir PagingAndSortingRepository onları destek vermesi halinde

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

, sen yazarlar ilişkilendirilecek bir yazarın URI ile kitap üzerinde bağlayıp bir PUT yapmak izleyin Kitabı GET olabilir. Öbür tarafa gidemezsin.

Bir Yazarda bir GET yapar ve kitaplarında bir PUT yaparsanız, yanıt 200 değerini döndürür, ancak ilişki hiçbir zaman kalıcı olmaz.

Beklenen davranış bu mu?

+2

Çift yönlü çağrışımların, genellikle setçilerin içinde yapılan nesne modelinde elle tutulması gerekir. Spring Data REST, alan erişimini varsayılan olarak kullanır. Derneklerdeki değişimin, dernek tarafından diğer tarafa da yansıtılmadığı anlamına gelir. Senkronizasyonu bir '@ PrePersist' /' @ PreUpdate' yönteminde denediniz mi? Veya mülk erişimine mi geçin? –

+1

İki yönlü ilişkiyi çözmek için de oy kullanacağım. “Yazar” bir “Kitap” olmadan var olabilir. 'Yazar' için bir' Yazar' bir depo yöntemi kullanılarak alınabilir ' BookRepository.findByAuthor (Yazar yazar)'. Bu, referansları elle tutmak zorunda kalmayacağınız için modeli oldukça basitleştirir. –

+0

Bir yazar bulmanız gereken bir kütüphane arayüzü görebiliyordum, sonra kitaplarını görebiliyordum. Bu iki yönlü dernekler olmadan desteklenmezdi. DATA REST'in amacı değilse, kuruluş ilişkilerini yönetme fanı değil. Girdiğin için teşekkürler, yazarların kitaplarının filtrelenmesi en iyi yaklaşım gibi görünüyor. Mümkün olduğunda işleri tek yönlü tutmamak. :) – keaplogik

cevap

24

tl; dr

Bunun anahtarı Bahar Veri REST çok şey değil - kolayca alabilirsiniz sizin senaryoda çalışmak - ama modeliniz dernek her iki ucunu tutar emin senkron.

Burada gördüğünüz sorun Bahar Veri DİNLENME temelde AuthorEntity ait books özelliğini değiştirir aslında doğar sorunu. Bu, bu güncelleştirmeyi BookEntity'un authors özelliğinde yansıtmaz. Bunun elle çalışılması gerekir. Bu, Spring Data REST'in oluşturduğu bir kısıtlama değil, JPA'nın genel olarak çalıştığı bir kısıtlamadır. Hatalı davranışı sadece setleyicileri manuel olarak çağırarak ve sonucu devam ettirmeye çalışarak çoğaltabileceksiniz.

Bu nasıl çözülür?

İki yönlü ilişkilendirmeyi kaldırmak bir seçenek değilse (bunu önerdiğim için aşağıya bakın), bu çalışmayı gerçekleştirmenin tek yolu, ilişkilendirmede değişikliklerin her iki tarafa yansıtıldığından emin olmaktır. Genellikle insanlar bir kitap eklendiğinde elle BookEntity konusu yazarı ekleyerek bu özen:

class AuthorEntity { 

    void add(BookEntity book) { 

    this.books.add(book); 

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

fıkra yanı sen emin olmak istiyorsanız BookEntity tarafta eklenecek giderdi eğer ek Diğer taraftan değişiklikler de yayılır. if temel olarak gereklidir, aksi takdirde iki yöntem sürekli olarak kendilerini çağırır.

Yay Verme DESTEĞİ, varsayılan olarak, bu mantığı gerçekten kullanabileceğiniz hiçbir yöntem olmaması için alan erişimini kullanır. Bir seçenek mülk erişimine geçmek ve mantığı ayarlayıcılara koymak olacaktır. Başka bir seçenek, varlıklar üzerinde yineleyen ve değişikliklerin her iki tarafa da yansıtmalarını sağlayan @PreUpdate/@PrePersist ile açıklamalı bir yöntem kullanmaktır. konuyla

Gördüğünüz gibi temel nedenini Çıkarma

, bu etki alanı modeline karmaşıklık oldukça fazla ekler.

# çift yönlü dernekler 1 kuralı: Dün Twitter'da espri yaptı gibi bunları kullanmayın ... :)

Eğer iki yönlü kullanmamaya çalışın eğer Genellikle konuyu kolaylaştırır Mümkün olduğu zaman ilişki ve derneğin arka tarafını oluşturan tüm varlıkları elde etmek için bir depoya geri dönün.

Hangi tarafın kesileceğini belirlemek, iyi bir sezgisel olup, derlemenin hangi tarafının modellendiğiniz etki alanı için gerçekten temel ve çok önemli olduğunu düşünmektir. Sizin durumunuzda, bir yazarın onun tarafından yazılmış bir kitap olmadan var olmasının mükemmel olduğunu iddia ederim. Kapak tarafında, yazar olmayan bir kitap hiç de fazla anlam ifade etmiyor. Bu yüzden BookEntity içinde authors özelliği tutmak ancak BookRepository üzerinde şu yöntemi tanıştırırdım:

interface BookRepository extends Repository<Book, Long> { 

    List<Book> findByAuthor(Author author); 
} 

Evet, şimdi bir depo ile çalışmak daha önce sadece author.getBooks() çağrılan olabilirdi tüm müşterilerine gerektirir. Ancak olumlu tarafta, tüm kabalıklarınızı etki alanlarınızdan kaldırdınız ve bu arada kitaptan yazara net bir bağımlılık yönü yarattınız. Kitaplar yazarlara dayanır, ancak diğer yoldan değil.

+4

Yanıtlarınızın "şablonu", bir şekilde SO: P'de standartlaştırılmalıdır. İyi şeyler! – geoand

+0

Size iyi bir şekilde okursam, tüm OneToMany ilişkilerini kaldırmayı ve yalnızca ManyToOne kolyesini tutmayı mı önereceksiniz? Bu, Varlık modelini oluşturma biçimimde gerçek bir değişiklik olacaktır ... –

+0

Hayır. İki yönlü dernek kullanmamanızı tavsiye ederim. Aslında, hiçbir ek açıklamadan bahsetmedim, bu yüzden bu yorumu nasıl elde ettiğinizi tam olarak anlayamadım. Kullandığınız derneğin hangi tarafının kullanım durumuna bağlı olduğu çok yüksektir. Lütfen gerekçelendirme için sezgisel yoldan bahseden bölümü tekrar okuyun. –

1

Benzer bir sorunla karşılaştığımda POJO'yu (bir çift yönlü mapping @OneToMany ve @ManyToOne) REST api üzerinden JSON olarak gönderirken, hem ana hem de çocuk varlıklardaki veriler devam etmekteydi ancak yabancı anahtar ilişkisi kurdu. Bu, çift yönlü ilişkilerin el ile sürdürülmesi gerektiğinden gerçekleşir.

JPA, açıklamalı yöntemin, varlık devam etmeden önce gerçekleştirildiğinden emin olmak için kullanılabilecek bir @PrePersist ek açıklaması sağlar. JPA ilk önce ana varlığı alt yapıyı çocuk varlığının takip ettiği veritabanına eklediğinden, @PrePersist no'lu açıklamalı bir yöntem ekledim. Bu, çocuk varlıkları listesi üzerinden yinelemeli ve ana öğeyi ona göre ayarlamalıdır.

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); 
    } 
} 

Bundan sonra o @JsonManagedReference ve @JsonBackReference ile çocuğunuzun sınıfına ile üst sınıfını açıklama önlemek için, sonsuz bir yineleme hata alabilirsiniz: Senin durumunda

böyle bir şey olurdu. Bu çözüm benim için çalıştı, umarım sizin için de çalışır.

İlgili konular