2012-10-24 33 views
8

Ich habe 2 Klassen: User und UserPicture, die eine 1: 1-Beziehung haben.Hibernate - bidirektionale @OneToOne

public class User { 
    @Id 
    @GeneratedValue(strategy=GenerationType.AUTO) 
    @Column(name="id", nullable = false, unique = true) 
private int id; 

    private String firstname; 

    private String lastname; 

    @OneToOne 
    @JoinColumn(name = "picture") //field named "picture" in the database 
    private UserPicture userPicture; 

    .. 
} 


public class UserPicture { 

    @Id 
    @GeneratedValue(strategy=GenerationType.AUTO) 
    @Column(name="id", nullable = false, unique = true) 
    private int id; 

    private Blob image; 

    @OneToOne 
    @JoinColumn(name = "user") 
    User user; 

'user' in UserPicture geladen werden, sondern 'userPicture' in Benutzer nicht - was Im falsch gemacht haben?

EDIT muss hinzufügen, dass Im nur einen UserPicture erstellen und einfügen (mit vorhandener userId) - vielleicht muß ich 'user' in UserPicture kaskadieren?

Antwort

14

Sie müssen Ihre Klassen zuordnen.

public class User { 
    ... 
    @OneToOne (mappedBy="user") 
    private UserPicture userPicture; 
    ... 
} 

public class UserPicture { 
    ... 
    @OneToOne 
    @JoinColumn (name="user") 
    private User user; 
    ... 
} 
+0

Es funktioniert! Vielen Dank! Aber wenn ich einen UserPicture-Benutzer einfüge wird nicht aktualisiert? – user1731299

+0

@ user1731299 Alles, was Sie tun müssen, um einen 'Benutzer' mit einem' UserPicture' zu ​​verbinden, ist ein 'UserPicture' zu ​​erstellen,' setUser' für das Objekt aufzurufen und in der Datenbank zu speichern. – Pigueiras

+0

Folgendes: Das Frontend fordert mich auf, ein Benutzerbild zu Benutzer A hinzuzufügen. In meinem Dienst lade ich Benutzer A neu, setze diesen Benutzer in mein neues UserPicture-Objekt und erstelle/platziere UserPicture -> Feld 'picture' in Tabelle user stay null. Wenn ein Benutzer geladen wird, ist das Bild geladen ... wirklich seltsam. – user1731299

2

In Bezug auf Ihre Frage:

„Alles klar, nur eine Frage mehr (weil ich in einem Kommentar nicht genug Ruf antworten), ist es möglich, userPicture in Benutzern zu machen faul - user1731299 24.10.12 um 10:44

Ja, es ist möglich, es faul holen zu machen. Das Aussprechen von "fetchType = FetchType.Lazy" funktioniert jedoch nicht. Grund dafür ist, dass Hibernate die verbundene Tabelle überprüfen muss, um festzustellen, ob es sich um einen Nullwert handelt oder ob dort ein Datensatz vorhanden ist. Da es sich um ein OneToOne-Mapping handelt, stellt Hibernate fest, dass es einen Datenbankaufruf speichern kann, indem es nur vorhandene Daten zurückzieht, da es prüfen musste, ob es ohnehin null war. Dies ist bei X-zu-Viele-Mappings nicht der Fall, da Hibernate weiß, dass das "Viele" bedeutet, dass eine Liste auf dem anderen Tisch wartet ... sei es eine leere oder eine ausgefüllte Liste, es ist immer noch eine Liste. Bei einem einzelnen Wert muss zwischen den tatsächlichen Daten und einem Nullwert unterschieden werden.

Der Weg um dies zu sagen ist Hibernate, dass dort immer ein Wert sein wird, und NIE ein Nullwert. Hibernate kann einen Platzhalter erstellen, bis es Zeit ist, diese Daten abzurufen. Die Art und Weise, wie Sie dies in Annotationen tun, ist das Hinzufügen von "optional = false" zu Ihrer @OneToOne Annotation.

Aber seien Sie gewarnt! Es gibt einige Probleme damit; einschließlich der, die ich jetzt herausfinden möchte (und wie ich dazu gekommen bin, über deine Frage hier zu stolpern). Diese Option = false bewirkt, dass Hibernate eine kleine zusätzliche Überprüfung durchführt und Hibernate dahingehend zu verwirren scheint, wie es Einfügungen ausführen soll. Also, du solltest dich vielleicht von dieser faulen Methode fernhalten.

1

Das verzögerte Laden in One to One funktioniert auch dann, wenn das Feld in der JoinColumn-Annotation als nicht nullbar angegeben wird. In einem bidirektionalen One-to-One funktioniert das Lazy Loading jedoch nicht in der Entity, in der wir mappedBy = '' verwenden. Zum Beispiel, wenn wir zwei Entitäten Contract und House haben, wobei die Contract-Tabelle einen Fremdschlüssel für House enthält. Wenn wir bidirektionale OneToOne hier verwenden und versuchen, einen Vertrag zu laden, funktioniert Lazy Loading (d. H. Haus wird nicht eifrig geladen), aber wenn wir versuchen, House zu laden (unter Verwendung von House-Repository), wird der Vertrag immer eifrig abgerufen. Hat jemand eine Idee, warum das passiert?

Public class Contract { 
    ..... 
    @onetoone(lazy) 
    @JoinColumn(name='houseid', nullable=false) 
    Private House house 
    ..... 
} 

Public class House { 
    ..... 
    @onetoone(lazy, mappedBy='house') 
    Private Contract contract 
    ..... 
} 

Ich weiß, das ist nur eine Teilantwort, cum Frage. Aber es hängt sehr stark mit der Diskussion hier zusammen.

Verwandte Themen