2012-06-09 14 views
14

Mam dwie klasy Foo i Bar. Tabele w bazie wyglądać następująco:Złożony klucz podstawowy, klucz obcy. Odniesienie do obiektu lub klucza?

|Foo| 
|id : INT (PK) | bar_id : INT (PK, FK) | 

|Bar| 
|id : INT (PK) | 

Normalnie bym map to tak:

@Entity 
public class Bar 
{ 
    @Id 
    @Column(name = "id") 
    private int id; 

    @OneToMany 
    private Set<Foo> foo; 
} 

@Entity 
public class Foo 
{ 
    @EmbeddedId 
    private FooPK key; 

    @MapsId("barId") 
    @ManyToOne 
    @JoinColumn(name = "bar_id", referencedColumnName = "id") 
    private Bar bar; 
} 

@Embeddable 
public class FooPK 
{ 
    @Column(name = "id") 
    private int id; 
    @Column(name = "bar_id") 
    private int barId; 
} 

Jednak id w FooPK odwzorowywane są luźno i muszą być połączone ręcznie. Wolałbym rozwiązanie, które mapuje używając obiektów zamiast luźnych identyfikatorów. Próbowałem następujących ale (oczywiście) to nie działa, ale myślę, że to daje wyobrażenie o tym, co chciałbym osiągnąć:

@Entity 
public class Bar 
{ 
    @Id 
    @Column(name = "id") 
    private int id; 

    @OneToMany 
    private Set<Foo> foo; 
} 

@Entity 
public class Foo 
{ 
    @EmbeddedId 
    private FooPK key; 

    @MapsId("barId") 
    @ManyToOne 
    @JoinColumn(name = "bar_id", referencedColumnName = "id") 
    @Access(AccessType.FIELD) 
    private Bar getBar() 
    { 
     return key.getBar(); 
    } 
} 

@Embeddable 
public class FooPK 
{ 
    @Column(name = "id") 
    private int id; 

    @Transient 
    private Bar bar; 

    //.... 

    @Column(name = "bar_id") 
    @Access(AccessType.PROPERTY) 
    private int getBarId 
    { 
     return bar.getId(); 
    } 
} 

Kolejny problem z tym ostatnim rozwiązania jest to, że sposób w getBarId()FooPK musi mieć metodę setBarId(Int). Ustawienie obiektu przy użyciu identyfikatora można wykonać, uzyskując dostęp do warstwy dostępu do danych, jednak to (moim zdaniem) narusza separację warstw biznesowych/domenowych/danych.

Co robić? Idź z pierwszym rozwiązaniem i synchronizuj identyfikatory ręcznie lub czy istnieje kolejna (najlepsza) praktyka?

Odpowiedz

23

Nawiązując do JPA 2: composite primary key classes dyskusji, wprowadzić następujące zmiany do klasy Foo i FooPK:

@Entity 
public class Foo { 

    @EmbeddedId 
    private FooPK key; 

    @MapsId("barId") //references EmbeddedId's property 
    @JoinColumn(name = "bar_id", referencedColumnName = "id") 
    @ManyToOne 
    private Bar bar; 
} 

@Embeddable 
public class FooPK { 

    @Column(name = "id") 
    private int id; 
    @Column(name = "bar_id") 
    private int barId; 
} 

Proponuję najpierw dzięki czemu praca z dostępem do pola, a następnie zastosować dostęp mienia.

Co robić? Idź z pierwszym rozwiązaniem i synchronizuj identyfikatory ręcznie lub czy istnieje kolejna (najlepsza) praktyka?

Uratuj się od bólu - automatycznie generuj identyfikatory.

+0

To pierwszy przykład. Widziałem, że jest to "droga do wyjścia", zastanawiałem się tylko, czy drugi przykład był czystszy. Chyba to nie jest? – siebz0r

+0

@ siebz0r oh, przepraszam, nie zauważyłem, pierwszy przykład był taki sam; Myślę, że łatwiej jest spojrzeć na PK, gdy są identyfikatory, a nie odwzorowane obiekty. Jeśli chcesz przeszukiwać FooPK, potrzebujesz tylko liczb całkowitych, a nie obiektów ze wszystkimi niepotrzebnymi właściwościami. – JMelnik