# Frage zu Hibernate-Mapping



## Verjigorm (27. Mrz 2011)

Hallo,
ich versuche mal kurz mein Problem mit Hibernate zu beschreiben. Dazu habe ich für mich persönlich gemerkt, dass ich vermutlich zu wenig Ahnung von Hibernate habe 

Habe 2 Tabellen A+B, habe beide Tabellen jede für sich gemappt, funktioniert soweit erstmal wunderbar (Klasse A und Klasse B).
Nun stehen A+B in einer 1:1-Beziehung zueinander und das wurde bisher noch nicht abgebildet.

Tabelle A hat einen einfachen PK, eine id-spalte. Diese habe ich ganz normal als "Long id" gemappt, mit @Id dran.

Tabelle B hat einen FK ref_id, der auf den PK von Tabelle A referenziert.

Diese 2 Spalten wurden vorher als ganz normale Longs abgebildet und händisch verwaltet. Möchte ich nun die Referenz von A -> B abbilden, so würde ja meine id aus Klasse A zu einer Referenz auf Klasse B. Wenn ich als jetzt noch @JoinColumn oder so hinzufüge, dann möchte das Hibernate aber nicht. Erscheint mir auch nicht ganz so logisch. Ich verliere ja so quasi gesehn meine Id.
Ich hab jetzt versucht das irgendwie abzubilden, aber Hibernate möchte keine meiner Lösungen akzeptieren  Kann mir soweit jemand helfen bei meiner "wirren" Erklärung?
Ansonsten werdeich am Montag mal mein Teststellung posten müssen.

mfg Verjigorm


----------



## mvitz (27. Mrz 2011)

Egal ob du das Mapping per XML oder per Annotationen machst.

Du solltest erst mal deinen Versuch posten 

EDIT: Seh gerade, dass du das morgen machst ^^...

Hast du denn auch mit @OneToOne gemapped?


----------



## Verjigorm (28. Mrz 2011)

Ok, ich merke grade, ich verstehe das Hibernate-System nicht wirklich 

Habe ein Minimalbeispiel gemacht.
Tabelle1 mit nur einer Spalte id (PK)
Tabelle2 mit 2 Spalten:
- id (PK)
- ref_id als FK auf Tabelle1

Das Mapping mit Annotationen habe ist unten. Bedingung sollte auch sein, dass TestMapping1 auf TestMapping2 zugreift, aber nicht umgekehrt.
Ich seh momentan den Wald vor lauter Bäumen nicht. Vielelciht sollte ich was anderes machen ...
Die Hibernateausgabe (gekürzt) sieht momentan wie folgt aus:



> Select * from test1 this_ left outer join test2 testmappin2_ on this_.id=testmappin2_.id where this_.id = 5



was ja falsch ist, da sollte doch stehen


> select * from test1 this_ left outer join test2 testmappin2_ on this_.id=testmappin2_.ref_id where this_.id = 5



dafür gibt es doch referencedColumnName oder nicht?
und generell passt es doch auch nicht, dass ich in TestMapping1 die Id und die Referenz auf TestMapping2 habe oder?

mfg Verjigorm


```
import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;

@Entity
@Table (name = "test1")
public class TestMapping1 implements Serializable
{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	@Id
	@Column (name = "id")
	private Long id;
	
	@OneToOne (fetch = FetchType.EAGER)
	@JoinColumn (name = "id",  referencedColumnName = "ref_id")
	private TestMapping2 test2;
	/**
	 * @param id the id to set
	 */
	public void setId(Long id) {
		this.id = id;
	}
	/**
	 * @return the id
	 */
	public Long getId() {
		return id;
	}
	/**
	 * @param test2 the test2 to set
	 */
	public void setTest2(TestMapping2 test2) {
		this.test2 = test2;
	}
	/**
	 * @return the test2
	 */
	public TestMapping2 getTest2() {
		return test2;
	}
	
}
```


```
import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table (name = "test2")
public class TestMapping2 implements Serializable
{
	/**
	 * 
	 */
	private static final long serialVersionUID = -1495990285243104362L;
	
	@Id
	@Column (name = "id")
	private Long id;
	
	@Column( name = "ref_id")
	private Long ref_id;
	
	/**
	 * @param id the id to set
	 */
	public void setId(Long id) {
		this.id = id;
	}
	/**
	 * @return the id
	 */
	public Long getId() {
		return id;
	}
	/**
	 * @param ref_id the ref_id to set
	 */
	public void setRef_id(Long ref_id) {
		this.ref_id = ref_id;
	}
	/**
	 * @return the ref_id
	 */
	public Long getRef_id() {
		return ref_id;
	}
	
}
```


----------



## SlaterB (28. Mrz 2011)

auf _ in irgendwas auf dieser Welt außer vielleicht statische Konstanten MAX_DATE und ähnliche Großschreibungen etwa von Attributen in DB-Tabellen solltest du verzichten, zumindest fürs Forum

-----

wie ist deine RefId zu verstehen, gibt es eine 1:1-Beziehung oder eine 1:n-Beziehung?
wenn Tabelle2 eine Id auf Tabelle1 hat wäre es natürlicher, eben in der Klasse TestMapping2  auf TestMapping1 zu verweisen statt umgekehrt?,
Hibernate kann allerdings durchaus bidirektional vervollständigen, na hast du ja im Grunde auch, beim Mapping wird nicht gemeckert?


wenn du SQL-Queries baust, dann haben die Hibernate-Klassen und Mappings quasi keine Bedeutung, 
in HQL musst du nicht unbedingt mit Ids hantieren, da sollte auch folgendes funktionieren:

```
select * from TestMapping1 one inner join one.test2 as two where one.id = 5
```
die Referenz auf TestMapping2 in TestMapping1 'test2' zu benennen, genau wie die DB-Tabelle, ist nicht gut


----------



## tfa (28. Mrz 2011)

@Verjigorm: Vielleicht hilft das ja:
http://www.java-forum.org/blogs/tfa/134-hibernate-mapping-1-1-unidirektional.html


----------



## mvitz (28. Mrz 2011)

Ist denn das Schema vorgegeben?

Weil das entspricht ja eigentlich nicht dem normalen OneToOne Mapping.
Da ist nämlich die Spalte, die die Beziehung angibt (bei dir ref_id) wie im Link von tfa zu sehen auf der "Besitzenden"-Seite (die in diesem Fall ja Test1 ist). Bei dir jedoch soll diese in Test2 obwohl du laut deiner Aussage nur von Test1 auf Test2 navigieren willst.

Beim normalen Fall sieht das Schema dann folgendermaßen bei mir aus (H2 Datenbank):


```
create table Test1 (id bigint generated by default as identity, test2_id bigint, primary key (id))
create table Test2 (id bigint generated by default as identity, primary key (id))
alter table Test1 add constraint FK4CF5DBF6D274EFD foreign key (test2_id) references Test2
```


----------



## mvitz (28. Mrz 2011)

Ansonsten geht das evtl so?


```
@Entity
public class Test1 {

    @Id
    @GeneratedValue
    private Long id;
    @OneToOne(mappedBy = "test1", fetch = FetchType.EAGER)
    private Test2 test2;

    public Long getId() {
        return id;
    }
    public void setId(Long aId) {
        id = aId;
    }
    public Test2 getTest2() {
        return test2;
    }
    public void setTest2(Test2 aTest2) {
        test2 = aTest2;
        test2.test1 = this;
    }
}
```


```
@Entity
public class Test2 {

    @Id
    @GeneratedValue
    private Long id;
    @OneToOne
    protected Test1 test1;

    public Long getId() {
        return id;
    }
    public void setId(Long aId) {
        id = aId;
    }
}
```


----------



## Verjigorm (28. Mrz 2011)

Hallo!

Ja, das Schema ist fest und es sind sich alle einig, dass es sch*** ist. Beim nächsten Versionssprung werden diese 2 Tabellen um die es momentan geht, die in einer 1:1-Verbindung zueinander stehen, auch zu einer zusammengefasst. Da die 2 Tabellen momentan auch redundante Daten etc. beinhalten.

Danke schonmal für die Hilfe, ihr habt mir jetzt schonmal soweit weitergeholfen, dass es funktioniert 

Nun habe ich noch ein kleines weiteres Problem:

Ich mache nun mit Hibernate ein save(test1). test2 soll dabei automatisch mitgespeichert werden. 
Momentan mache ich nach dem save(test1) noch ein save(test1.getTest2()) ....
Soweit ich weiss, ist doch cascade dafür verantwortlich oder nicht? Habe nun CascadeType.Persist und CascadeType.ALL versucht, aber beiden will nicht.

Wie mach ich das denn nun?

mfg Verjigorm


----------



## mvitz (28. Mrz 2011)

Wenn ich mich richtig erinnere, dann hängt das Cascade von der Besitzendenseite ab.

Wenn du das jetzt so gelöst hast, wie ich oben gepostet habe, dann ist Test2 die besitzende-Seite und wenn du Test2 speicherst, sollte Test1 mitgespeichert werden.


----------



## Verjigorm (28. Mrz 2011)

Nein, habs andersrum, Test1 ist die Besitzendenseite.
Ich geb da doch auch den FetchType.EAGER an, dann muss das doch auch beim Speichern klappen oder?


----------



## mvitz (28. Mrz 2011)

Eigentlich funktioniert das schon mit dem Kaskadieren. Wie sehen denn aktuell deine Klassen aus?

Anbei mal ein Beispiel von mir (nutze allerdings nicht direkt Hibernate sondern JPA)


```
@Entity
public class Test1 {

    @Id
    @GeneratedValue
    private Long id;
    @OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST)
    private Test2 test2;

    public Long getId() {
        return id;
    }
    public void setId(Long aId) {
        id = aId;
    }
    public Test2 getTest2() {
        return test2;
    }
    public void setTest2(Test2 aTest2) {
        test2 = aTest2;
    }
}
```


```
@Entity
public class Test2 {

    @Id
    @GeneratedValue
    private Long id;

    public Long getId() {
        return id;
    }
    public void setId(Long aId) {
        id = aId;
    }
}
```


```
public class Main {
    public static void main(String[] args) {
        EntityManager em = Persistence.createEntityManagerFactory("TEST").createEntityManager();

        Test2 test2 = new Test2();
        Test1 test1 = new Test1();
        test1.setTest2(test2);

        em.getTransaction().begin();
        em.persist(test1);
        em.flush();
        em.getTransaction().commit();

        em.clear();

        Test2 test2new = em.find(Test2.class, 1L);
        System.out.println(test2new.getId());

        Test1 test1new = em.find(Test1.class, 1L);
        System.out.println(test1new.getId());
        System.out.println(test1new.getTest2().getId());
    }
}
```


----------



## Verjigorm (29. Mrz 2011)

Hallo,

danke an alle, funktioniert jetzt erstmal soweit alles

mfg Verjigorm


----------

