OneToMany undirektional

Hallo zusammen, ich hab hier ein kleines ausführbares Beispiel.
Irgendwie komm ich mit dem cascade und einer einfachen 1:n Beziehung nicht klar.
Ich versteh nicht, dass wenn ich eine Instanz von A erzeug und dann ein B hinzufüge, dass es zwar in a, dass b drin ist ABER nichts in der DB gespeichert ist warum???
Wenn ich aber davor das A suche und dann die gleiche Methode ausführe dann funktioniert es WARUM :confused: ich verstehs nicht so ganz…
Was mache ich falsch?? Oder gibt es eine bessern Ansatz? Weil ich würde gerne die Instanz dann eventuell in einem Model oder sontigem speichern aber bringt ja nichts, wenn dann nie was in der DB ankommt… Freue mich für jede Hilfe…
Wenn man das auskommentierte einkommentiert sieht man die beiden Fälle ganz schön.


package hibernate;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name = "A")
public class A implements Serializable {

    private Integer id;
    private List<B> bs ;
    
    public A()
    {
        super();
        bs = new ArrayList<B>();
    }
   
    @Id
    @GeneratedValue
    public Integer getId() {
        return id;
    }
    
    public void setId(Integer id) {
        this.id = id;
    }
    
    @OneToMany(cascade = CascadeType.ALL)
    public List<B> getBs() {
        return bs;
    }

    
    public void setBs(List<B> bs) {
        this.bs = bs;
    }

    public void addB(B b) {
        bs.add(b);
    }

    public void removeB(B b) {
        bs.remove(b);
    }

}

package hibernate;

import java.io.Serializable;

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

@Entity
@Table(name = "B")
public class B implements Serializable{

    private Integer id;
    private Double value;
    private String reason;

    public void setId(Integer id) {
        this.id = id;
    }
    @Id
    @GeneratedValue
    public Integer getId() {
        return id;
    }
    public void setValue(Double value) {
        this.value = value;
    }
    public Double getValue() {
        return value;
    }
    public void setReason(String reason) {
        this.reason = reason;
    }
    public String getReason() {
        return reason;
    }
}


package hibernate;

import org.hibernate.*;
import org.hibernate.cfg.*;

public class HibernateUtil {

    private static  SessionFactory sessionFactory;

    public static void connect()
    {
        try {
            // Create the SessionFactory from hibernate.cfg.xml
            sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
        } catch (Throwable ex) {
        	ex.printStackTrace();
            // Make sure you log the exception, as it might be swallowed
            System.err.println("Initial SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }

}


package hibernate;

import org.hibernate.Session;

public class Main {

    public static void main(String[] args) {
        try {
            HibernateUtil.connect();
            A a = new A();
            createA(a);
            
            //würde gehen a = findA(0);
            B b = new B();
            b.setReason("test");
            b.setValue(3.0);
            addB(b, a);
            System.out.println("a " + a.getBs().size()); 
            System.out.println("find " + findA(1).getBs().size()); 
        } catch (Exception e) {
            e.printStackTrace();
            HibernateUtil.getSessionFactory().close();
        }

    }
    

    public static void createA(A a) {
        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        session.beginTransaction();
        session.save(a);
        session.getTransaction().commit();
    }

    public static A findA(Integer id) {
        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        session.beginTransaction();
        return (A) session.load(A.class, id);
    }

    public static void addB(B b, A a) {
        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        session.beginTransaction();
        a.addB(b);
        session.getTransaction().commit();
    }

}



<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

    <session-factory>

        <!-- Database connection settings -->
        <property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
        <property name="connection.url">jdbc:hsqldb:hsql://localhost</property>
        <property name="connection.username">sa</property>
        <property name="connection.password"></property>

        <!-- JDBC connection pool (use the built-in) -->
        <property name="connection.pool_size">1</property>

        <!-- SQL dialect -->
        <property name="dialect">org.hibernate.dialect.HSQLDialect</property>

        <!-- Enable Hibernate's automatic session context management -->
        <property name="current_session_context_class">thread</property>

        <!-- Disable the second-level cache  -->
        <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>

        <!-- Echo all executed SQL to stdout -->
        <property name="show_sql">true</property>

        <!-- Drop and re-create the database schema on startup -->
        <property name="hbm2ddl.auto">create</property>
        
		<!--<property name="hibernate.archive.autodetection" value="class" />-->
        <mapping class="hibernate.A"/>
        <mapping class="hibernate.B"/>
    </session-factory>

</hibernate-configuration>

Ich seh jetzt nicht wie du deinen Fall machst der wohl nicht geht.

A a = new A();
B b = new B();
a.add(b);
save(a);

das sollte eigentlich gehen

[quote=EagleEye]Ich seh jetzt nicht wie du deinen Fall machst der wohl nicht geht.
Java

  1. A a = new A();
  2. B b = new B();
  3. a.add(b);
  4. save(a);

das sollte eigentlich gehen[/quote]

Dass das geht ist mir klar…
Aber ich lege erst A an und im weiteren Ablauf werden die B’s erst hinzugefügt.
Das sollte doch irgendwie gehen.

Wie du siehst den Fall nicht der nicht geht??

ach jetzt seh ich das du musst update(a) machen damit die Änderungen an a in der Datenbank gespeichert werden.

Ja okay alles klar… nachdem ich ein commit gemacht habe ist a der session nicht mehr bekannt weil commit ein flush macht. Und deshalb muss ich a der session ersteinmal wieder bekannt machen.
Merge oder Update?

genau
hmm das nimmt sich nicht viel, merge ist glaube wenn sich auf der Datenbank was geändert haben könnte.

[QUOTE=EagleEye]genau
hmm das nimmt sich nicht viel, merge ist glaube wenn sich auf der Datenbank was geändert haben könnte.[/QUOTE]

Ja merge ist ganz schlecht ^^…
Nachdem unteren commit ist B nicht mehr der session bekannt.
und bei einem merge wird gesucht ob a der session bekannt ist -->NEIN, und da b auch nicht mehr bekannt ist legt er es nochmal an so hat man am schluß 3bs in der DB, aber die beziehung ist noch richtig … kannst ja einfach ausprobieren ist ziemlich interessant :D…
aber langsam kommt ein bischen licht ins dunkle :wink: dank dir

Mal ne Frage wo hast du deine Hibernate aufrufe? z.B. commits und wo du Objekte persitenz machst? im Model oder im Controller?

ich arbeite mit Spring :wink:
Aber wenn dann hätte ich dafür eine gesonderte Klasse die das alles übernimmt.

Sollte mir auch mal Spring anschauen ;)…
Ja gesonderte Klasse ist mir klar, aber irgendwo musst die Aufrufe ja machen :wink:

Naja diese Aufrufe werden halt in der Klasse gemacht :wink:

Also das mit dem update war auch nicht das richtige, es gibt nämlich 2 möglicheiten entweder ich leg das Objekt neu an oder es liegt schon in der DB. Wenn der 2te Fall eintritt lad ich es mit session.load()… und dann ist es der session bekannt und dann knallts beim update, dass er das Objekt schon kennt…ich hab jetzt einfach ein session.refresh() aufgerufen damit funzt es in beiden Fällen =) =)…