# Hibernate: StaleStateException



## KlinCh (25. Mai 2009)

Hi,
Ich hab wiedereinmal Probleme mit Hibernate.
Im Prinzip soll die Methode createUser() einfach nur einen neuen Player in die Datenbank speichern.
Dabei bekomme ich aber immer diese Exception, die ich mir nicht erklären kann, da ich ja gar nichts update???.

```
org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
        at org.hibernate.jdbc.Expectations$BasicExpectation.checkBatched(Expectations.java:61)
        at org.hibernate.jdbc.Expectations$BasicExpectation.verifyOutcome(Expectations.java:46)
        at org.hibernate.jdbc.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:24)
        at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2403)
        at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:2307)
        at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2607)
        at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:92)
        at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:250)
        at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:234)
        at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:142)
        at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
        at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
        at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
        at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
        at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
        at mySchool.core.Database.createUser(Database.java:78)
```

die Funktion createUser:

```
public static Player getPlayer(String username, String password) {

        Session session = InitHibernate.getSessionFactory().getCurrentSession();
        session.beginTransaction();
        Query query = session.createQuery("select u from mySchool.gameObjects.Player as u where u.name=:username and u.password=:password");
        query.setString("username", username);
        query.setString("password", password);
        boolean b = true;

        Player player = null;
        if(query.list().size() >= 1){
            player = (Player) query.uniqueResult();
        }

        session.getTransaction().commit();
        return player;

       
        
    }
    public static void createUser(String username, String email, String password, Region region) throws UserDoesAlreadyExistException {

       
        if (getPlayer(username, password) == null) {
            Session session = InitHibernate.getSessionFactory().getCurrentSession();
            session.beginTransaction();
            Player p = new Player();
            session.save(p);
            p.setName(username);
            p.setPassword(password);
            p.setEmail(email);
            p.setRegion(region);
          
            session.getTransaction().commit();
        } else {
            throw new UserDoesAlreadyExistException();
        }
    }
```

Wisst ihr wo der Fehler liegt?
Falls ihr noch mehr Code braucht, fragen oder einfach anonym das svn-repo checken:
myschool - Revision 74: /

Danke schonmal


----------



## SlaterB (25. Mai 2009)

es wird anscheinend ein Player-Objekt geupdated, welches keine Id hat, daher schlägt das Update fehl,

setze die Daten vor dem Save, dann ist später kein Update nötig,
oder prüfe nach, ob das Player-Objekt beim Save automatisch eine Id erhielt, falls diese überhaupt konfiguriert ist


----------



## KlinCh (25. Mai 2009)

Danke,

Also an einer fehlenden PlayerId liegt es nicht:

```
...
@Entity(name="TUSER")
@SequenceGenerator(sequenceName="tuser_id_seq", name="user_id")
public class Player implements Serializable{

    @Id
    @GeneratedValue(generator="user_id", strategy=GenerationType.AUTO)
    int id;
...
```

Aber mir ist noch etwas eingefallen, ich hab das p.setRegion(region) mal auskommentiert und siehe da es läuft reibungslos. 

Ich schau erstmal selber, wenn ichs jetzt den Fehler nicht finde, dann meld ich mich nochmal.


----------



## KlinCh (25. Mai 2009)

Ok, ich kriegs doch nicht alleine hin :-(

also das mit Region ist so ne Sache also das Objekt, das createUser() bekommt ist statisch.
(alle Regionen kommen hardgecoded als statische Objekte vor)

Jetzt 2 Fragen:
1. Es müsste doch möglich sein diese abzuspeichern, oder?
2. Es funktioniert nicht, dass eine Hibernate-Entity eine Beziehung zu einem statischen Objekt hat, oder ?

aber:
ich hab probiert vor dem .save(p) noch ein .save(region) zu machen.
Hilft aber anscheinend auch nicht weiter.


----------



## SlaterB (26. Mai 2009)

habe ich nicht eindeutige Anweisungen gegeben?

p.setName(username);
            p.setPassword(password);
            p.setEmail(email);
            p.setRegion(region);


VOR

 session.save(p);


--------

außerdem/ alternativ nachschauen, ob p nach dem save() eine Id != 0 hat


----------



## KlinCh (26. Mai 2009)

Doch hast du.
Mein Code sieht ja auch so aus:

```
public static void createUser(String username, String email, String password, Region region) throws UserDoesAlreadyExistException {

       
        if (getPlayer(username, password) == null) {
            Session session = InitHibernate.getSessionFactory().getCurrentSession();
            session.beginTransaction();
            Player p = new Player();
            p.setName(username);
            p.setPassword(password);
            p.setEmail(email);
            p.setRegion(region);

            session.save(p);
            session.getTransaction().commit();
        } else {
            throw new UserDoesAlreadyExistException();
        }
    }
```


----------



## SlaterB (26. Mai 2009)

und gibt es noch eine Exception, die vom Anfang?

hat es was mit der Region zu tun, funktioniert das ganze, wenn du keine Region setzt, gar Region ganz aus dem Mapping entfernst?

wie sind Player und Region definiert/ gemappt?


----------



## KlinCh (26. Mai 2009)

Also die Exception bleibt die selbe,
wenn ich (wie oben beschrieben) die Region nicht setzte, dann gibt es kein Problem.

Ich poste jetzt mal den Quellcode von Player und Region:
Player:

```
@Entity(name="TUSER")
@SequenceGenerator(sequenceName="tuser_id_seq", name="user_id")
public class Player implements Serializable{

    @Id
    @GeneratedValue(generator="user_id", strategy=GenerationType.AUTO)
    int id;
    String name;
    String password;
    String email;
    String profile;

    @OneToOne(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
    Building building = new Building();
    private double money = Configuration.getStartMoney();
    private long points = 0;
    private int roomForStudents =20;

//        @OneToMany
//    private Set<Staff> staff = new HashSet<Staff>();
        @OneToOne(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
    private Score score = new Score();

        @OneToOne(fetch=FetchType.EAGER, cascade=CascadeType.ALL)
    private Skill skill = new Skill();
//        @OneToMany(mappedBy="receiver")
//    private Set<Message> messages = new HashSet<Message>();

        @OneToMany(mappedBy="player", cascade=CascadeType.ALL)
    private Set<Calculation> calculations = new HashSet<Calculation>();

        @ManyToOne(fetch=FetchType.EAGER, cascade=CascadeType.ALL)
    private Region region;

    /* alles für die ChaosEvents */
        @OneToOne(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
    private ChaosEvent currentChaosEvent = null;

        @Temporal(javax.persistence.TemporalType.DATE)
    private Date lastChaosEvent = new Date();

        @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
    private Set<ChaosEvent> alreadyHappenedChaosEvents = new HashSet<ChaosEvent>();



        
     public Player() {
      
    }
```
und Region:

```
@Entity
@SequenceGenerator(name="region_id", sequenceName="region_id_seq")
public class Region implements Serializable{

    @Id
    @GeneratedValue(generator="region_id", strategy=GenerationType.AUTO)
    private int id;
    
    @Transient
    static public ArrayList<Region> allRegions = new ArrayList<Region>();

    @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
    private Set<Subject> subjects = new LinkedHashSet<Subject>();
    private String name;
    private double funds;   // Zuschüsse vom Staat
    private double securityFactor;

    public double getFunds() {
        return funds;
    }

    public void setFunds(double funds) {
        this.funds = funds;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getSecurityFactor() {
        return securityFactor;
    }

    public void setSecurityFactor(double securityFactor) {
        this.securityFactor = securityFactor;
    }

    public Set<Subject> getSubjects() {
        return subjects;
    }



   @Transient
    public static Region BAWU = new Region("Baden-Württemberg", 1000.0, 1.5,
            new Subject("Geschichte", 6),
            new Subject("Sport", 3)
           );

   @Transient
    public static Region Frankfurt = new Region("Frankfurt", 100.0, 0.8,
    new Subject("Wirtschaft", 7),
    new Subject("Mathe", 4)
           );
...

    public Region () {
       
    }
    public Region(String name, double funds, double secFactor, Subject... someSubjects){
        allRegions.add(this);
        this.funds = funds;
        this.name = name;
        this.securityFactor = secFactor;
        for(Subject s : someSubjects){
            subjects.add(s);
        }
        
    }
```

Sorry, ist jetzt ein bisschen viel Code, aber ich weiss mir nicht anders zu helfen, als Leute hier im Forum zu nerven.


----------



## SlaterB (26. Mai 2009)

setze testweise nicht die statische alte Region, sondern lade über die Session das aktuelle Objekt zur fraglichen Id,
(zum xy. mal wie immer der Hinweis, von allen Objekten überhaupt mal die Id auszugeben  ) und speichere das aktuelle Objekt

-------

im Internet findet man zu der Exception hauptsächlich delete-Fehler


>     @ManyToOne(fetch=FetchType.EAGER, cascade=CascadeType.ALL)
>    private Region region;

das Cascade wundert mich, die Region ist doch unabhängig von Player, existiert auch ohne diese?
durch das Cascade wurde die Region vielleicht irgendwann in der Datenbank gelöscht, ist gar nicht mehr bekannt, nur noch in der statischen Liste vorhanden?
wurden die Regionen überhaupt vorher gespeichert, haben sie eine Id?

das sind aber langsam sehr viele Vermutungen, ich glaube das ist aus der Ferne nicht mehr richtig effektiv


----------



## KlinCh (26. Mai 2009)

SlaterB hat gesagt.:


> setze testweise nicht die statische alte Region, sondern lade über die Session das aktuelle Objekt zur fraglichen Id,



Yes, das wars !
Ich hab jetzt in meiner Database.java einen statischen Block eingefügt, der zuerst einmal alles was irgendwie statisch ist, in die datenbank speichert bzw. updated. Nun funktioniert es.

Das Cascading war natürlich blöd, hab ich jetzt auch weggemacht.

Danke, Danke, Danke.


----------



## KlinCh (27. Mai 2009)

Ok, jetzt das erstmalige Laden in die DB geht doch nicht ganz reibungslos.
Und ich hab wiedermal keine ahnung.
Meine Database.java sieht jetzt so aus:


```
public class Database {

    static boolean isInitializised = false;
    
    static {
        if(isInitializised == false){
            initialize();
        }
    }
    public static void initialize(){
        Logger logger = Logger.getLogger(Database.class.getName());
        logger.log(Level.INFO, "Initializising Database");
        isInitializised = true;
        Session session = InitHibernate.getSessionFactory().getCurrentSession();
        session.beginTransaction();
        try{
            /* Läd alle Fächer in die Datenbank */
            logger.log(Level.INFO, "Loading all Subjects into DB");
            for(Subject s : Subject.allSubjects){
                logger.log(Level.INFO, "saveOrUpdate Subject :"+s.toString()+", ID: "+s.getId());
               session.update(s);
           }
           
            /* Läd alle Regionen in die Datenbank */
            logger.log(Level.INFO, "Loading all Regions into DB");
            for(Region r : Region.allRegions){
                session.saveOrUpdate(r);
                logger.log(Level.INFO, "saveOrUpdate Region :"+r.toString()+", ID: "+r.getId());
            }
            /* Läd alle ChaosEvents in die Datenbank */
            logger.log(Level.INFO, "Loading all ChaosEvetns into DB");
            for(ChaosEvent ce : ChaosEvent.allChaosEvents){
                session.saveOrUpdate(ce);
                logger.log(Level.INFO, "saveOrUpdate ChaosEvent :"+ce.toString()+", ID: "+ce.getId());
            }

            

            session.getTransaction().commit();
            logger.log(Level.INFO, "Initializising Database: successfull");

        } catch(HibernateException ex){
            session.getTransaction().rollback();
            ex.printStackTrace();
            logger.log(Level.WARNING, "Initializising Database: error");
        }
    }

    public static List<Region> getRegions(){
        Session s = InitHibernate.getSessionFactory().getCurrentSession();
        s.beginTransaction();
        Query q = s.createQuery("select r from mySchool.gameObjects.Region as r");
        List<Region> list = q.list();
        s.getTransaction().commit();
        return list;
    }

    /**
     *
     * @param username: String username
     * @param password: String password
     * @return the player from the database maybe <code>null</code>
     *
     */
    public static Player getPlayer(String username, String password) {

        Session session = InitHibernate.getSessionFactory().getCurrentSession();
        session.beginTransaction();
        Query query = session.createQuery("select u from mySchool.gameObjects.Player as u where u.name=:username and u.password=:password");
        query.setString("username", username);
        query.setString("password", password);
        boolean b = true;

        Player player = null;
        if(query.list().size() >= 1){
            player = (Player) query.uniqueResult();
        }

        session.getTransaction().commit();
        return player;

       
        
    }
    public static Player authentificate(String username, String password) throws WrongUserNameOrPasswordException{

        boolean isPlayer = false;
         Player player = getPlayer(username, password);
         isPlayer = player != null;
         Logger.getLogger(Database.class.getName())
                .log(Level.FINE, ("Authentifikation: "+username+" succesfull: "+isPlayer));
         if(isPlayer){
             return player;
         } else {
             throw new WrongUserNameOrPasswordException();
         }
    }


    public static void createUser(String username, String email, String password, Region region) throws UserDoesAlreadyExistException {

        
        if (getPlayer(username, password) == null) {
            Session session = InitHibernate.getSessionFactory().getCurrentSession();
            session.beginTransaction();
            Player p = new Player();

            p.setName(username);
            p.setPassword(password);
            p.setEmail(email);
            p.setRegion(region);

            session.save(p);

             Logger.getLogger(Database.class.getName())
                .log(Level.FINE, ("User succesfully created: "+p.getId()+", "+p.getName()+", "+p.getEmail()));
             
            session.getTransaction().commit();
        } else {
            throw new UserDoesAlreadyExistException();
        }
    }
}
```

und die Exception ist wieder eine StaleException aber jetzt sieht das ein bisschen anders aus:

```
INFO: schema update complete
27.05.2009 16:13:27 mySchool.core.Database initialize
INFO: Loading all Subjects into DB
27.05.2009 16:13:27 mySchool.core.Database initialize
INFO: saveOrUpdate Subject :Mathe, ID: 1
27.05.2009 16:13:27 mySchool.core.Database initialize
INFO: saveOrUpdate Subject :Deutsch, ID: 2
27.05.2009 16:13:27 mySchool.core.Database initialize
INFO: saveOrUpdate Subject :Französisch, ID: 3
27.05.2009 16:13:27 mySchool.core.Database initialize
INFO: saveOrUpdate Subject :Englisch, ID: 4
27.05.2009 16:13:27 mySchool.core.Database initialize
INFO: saveOrUpdate Subject :Sport, ID: 5
27.05.2009 16:13:27 mySchool.core.Database initialize
INFO: Loading all Regions into DB
27.05.2009 16:13:28 mySchool.core.Database initialize
INFO: saveOrUpdate Region :Baden-Württemberg, ID: 453
27.05.2009 16:13:28 mySchool.core.Database initialize
INFO: Loading all ChaosEvetns into DB
27.05.2009 16:13:28 mySchool.core.Database initialize
INFO: saveOrUpdate ChaosEvent :Schlägerei, ID: 1
27.05.2009 16:13:28 mySchool.core.Database initialize
INFO: saveOrUpdate ChaosEvent :Mobbing in der 7a, ID: 2
27.05.2009 16:13:28 org.hibernate.util.JDBCExceptionReporter logExceptions
[B]WARNUNG:[/B] SQL Error: -1, SQLState: 23503
27.05.2009 16:13:28 org.hibernate.util.JDBCExceptionReporter logExceptions
SCHWERWIEGEND: INSERT in Tabelle 'REQUIREMENT' hat für Schlüssel (2) die Integritätsbedingung 'FK7912842313767E40' für Fremdschlüssel verletzt. Die Anweisung wurde zurückgesetzt.
27.05.2009 16:13:28 org.hibernate.event.def.AbstractFlushingEventListener performExecutions
[B]SCHWERWIEGEND: [/B]Could not synchronize database state with session
org.hibernate.exception.ConstraintViolationException: could not insert: [mySchool.gameObjects.util.Requirement]
        at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71)
        at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
        at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2267)
        at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2660)
        at org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:56)
        at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:250)
        at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:234)
        at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:141)
        at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
        at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
        at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
        at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
        at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
        at mySchool.core.Database.initialize(Database.java:70)
        at mySchool.core.Database.<clinit>(Database.java:38)
        at mySchool.core.Test.main(Test.java:29)
Caused by: java.sql.SQLIntegrityConstraintViolationException: INSERT in Tabelle 'REQUIREMENT' hat für Schlüssel (2) die Integritätsbedingung 'FK7912842313767E40' für Fremdschlüssel verletzt. Die Anweisung wurde zurückgesetzt.
        at org.apache.derby.client.am.SQLExceptionFactory40.getSQLException(Unknown Source)
        at org.apache.derby.client.am.SqlException.getSQLException(Unknown Source)
        at org.apache.derby.client.am.PreparedStatement.executeUpdate(Unknown Source)
        at org.hibernate.jdbc.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:23)
        at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2247)
        ... 13 more
Caused by: org.apache.derby.client.am.SqlException: INSERT in Tabelle 'REQUIREMENT' hat für Schlüssel (2) die Integritätsbedingung 'FK7912842313767E40' für Fremdschlüssel verletzt. Die Anweisung wurde zurückgesetzt.
        at org.apache.derby.client.am.Statement.completeExecute(Unknown Source)
        at org.apache.derby.client.net.NetStatementReply.parseEXCSQLSTTreply(Unknown Source)
        at org.apache.derby.client.net.NetStatementReply.readExecute(Unknown Source)
        at org.apache.derby.client.net.StatementReply.readExecute(Unknown Source)
        at org.apache.derby.client.net.NetPreparedStatement.readExecute_(Unknown Source)
        at org.apache.derby.client.am.PreparedStatement.readExecute(Unknown Source)
        at org.apache.derby.client.am.PreparedStatement.flowExecute(Unknown Source)
        at org.apache.derby.client.am.PreparedStatement.executeUpdateX(Unknown Source)
        ... 16 more
org.hibernate.exception.ConstraintViolationException: could not insert: [mySchool.gameObjects.util.Requirement]
        at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71)
        at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
        at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2267)
        at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2660)
        at org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:56)
        at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:250)
        at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:234)
        at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:141)
        at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
        at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
        at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
        at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
        at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
        at mySchool.core.Database.initialize(Database.java:70)
        at mySchool.core.Database.<clinit>(Database.java:38)
        at mySchool.core.Test.main(Test.java:29)
Caused by: java.sql.SQLIntegrityConstraintViolationException: INSERT in Tabelle 'REQUIREMENT' hat für Schlüssel (2) die Integritätsbedingung 'FK7912842313767E40' für Fremdschlüssel verletzt. Die Anweisung wurde zurückgesetzt.
        at org.apache.derby.client.am.SQLExceptionFactory40.getSQLException(Unknown Source)
        at org.apache.derby.client.am.SqlException.getSQLException(Unknown Source)
        at org.apache.derby.client.am.PreparedStatement.executeUpdate(Unknown Source)
        at org.hibernate.jdbc.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:23)
        at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2247)
        ... 13 more
Caused by: org.apache.derby.client.am.SqlException: INSERT in Tabelle 'REQUIREMENT' hat für Schlüssel (2) die Integritätsbedingung 'FK7912842313767E40' für Fremdschlüssel verletzt. Die Anweisung wurde zurückgesetzt.
        at org.apache.derby.client.am.Statement.completeExecute(Unknown Source)
        at org.apache.derby.client.net.NetStatementReply.parseEXCSQLSTTreply(Unknown Source)
        at org.apache.derby.client.net.NetStatementReply.readExecute(Unknown Source)
        at org.apache.derby.client.net.StatementReply.readExecute(Unknown Source)
        at org.apache.derby.client.net.NetPreparedStatement.readExecute_(Unknown Source)
        at org.apache.derby.client.am.PreparedStatement.readExecute(Unknown Source)
        at org.apache.derby.client.am.PreparedStatement.flowExecute(Unknown Source)
        at org.apache.derby.client.am.PreparedStatement.executeUpdateX(Unknown Source)
        ... 16 more
27.05.2009 16:13:28 mySchool.core.Database initialize
WARNUNG: Initializising Database: error
27.05.2009 16:13:28 mySchool.core.Database initialize
INFO: Initializising Database
27.05.2009 16:13:28 mySchool.core.Database initialize
INFO: Loading all Subjects into DB
27.05.2009 16:13:28 mySchool.core.Database initialize
INFO: saveOrUpdate Subject :Mathe, ID: 1
27.05.2009 16:13:28 mySchool.core.Database initialize
INFO: saveOrUpdate Subject :Deutsch, ID: 2
27.05.2009 16:13:28 mySchool.core.Database initialize
INFO: saveOrUpdate Subject :Französisch, ID: 3
27.05.2009 16:13:28 mySchool.core.Database initialize
INFO: saveOrUpdate Subject :Englisch, ID: 4
27.05.2009 16:13:28 mySchool.core.Database initialize
INFO: saveOrUpdate Subject :Sport, ID: 5
27.05.2009 16:13:28 mySchool.core.Database initialize
INFO: Loading all Regions into DB
27.05.2009 16:13:28 mySchool.core.Database initialize
INFO: saveOrUpdate Region :Baden-Württemberg, ID: 453
27.05.2009 16:13:28 mySchool.core.Database initialize
INFO: Loading all ChaosEvetns into DB
27.05.2009 16:13:28 mySchool.core.Database initialize
INFO: saveOrUpdate ChaosEvent :Schlägerei, ID: 1
27.05.2009 16:13:28 mySchool.core.Database initialize
INFO: saveOrUpdate ChaosEvent :Mobbing in der 7a, ID: 2
27.05.2009 16:13:28 org.hibernate.event.def.AbstractFlushingEventListener performExecutions
[B]SCHWERWIEGEND:[/B] Could not synchronize database state with session
org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
        at org.hibernate.jdbc.Expectations$BasicExpectation.checkBatched(Expectations.java:61)
        at org.hibernate.jdbc.Expectations$BasicExpectation.verifyOutcome(Expectations.java:46)
        at org.hibernate.jdbc.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:24)
        at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2403)
        at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:2307)
        at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2607)
        at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:92)
        at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:250)
        at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:234)
        at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:142)
        at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
        at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
        at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
        at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
        at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
        at mySchool.core.Database.initialize(Database.java:70)
        at mySchool.core.Test.main(Test.java:29)
org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
        at org.hibernate.jdbc.Expectations$BasicExpectation.checkBatched(Expectations.java:61)
        at org.hibernate.jdbc.Expectations$BasicExpectation.verifyOutcome(Expectations.java:46)
        at org.hibernate.jdbc.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:24)
        at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2403)
        at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:2307)
        at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2607)
        at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:92)
        at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:250)
        at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:234)
        at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:142)
        at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
        at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
        at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
        at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
        at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
        at mySchool.core.Database.initialize(Database.java:70)
        at mySchool.core.Test.main(Test.java:29)
27.05.2009 16:13:28 mySchool.core.Database initialize
WARNUNG: Initializising Database: error
```

Wenn der Code nicht ausreicht dann poste ich noch mehr, oder wahrscheinlich geschickter, aber ich weiss nicht wieviel arbeit es dir macht, könntest du ihn komplett auch von meinem svn-repo holen:
myschool - Revision 78: /


----------



## SlaterB (27. Mai 2009)

die Fehlermeldung spricht von Requirement und die Klasse postest du nicht?
ok, offizielle Anforderung: Code reicht nicht aus, bitte poste mehr

ich vermute:
Requirement referenziert andere Objekte, die nicht vorher in der DB gespeichert wurden,
alternativ vielleicht als 'CASCADE INSERT' oder änhlich definieren, so dass automatisch inserted wird,


----------



## KlinCh (27. Mai 2009)

Die Regionen liegen so vor:
(Auszug aus Region.java)

```
public static Region BAWU = new Region(1, "Baden-Württemberg", 1000.0, 1.5,
            new Requirement(Subject.MATH, 5),
            new Requirement(Subject.GERMAN, 3)
           );
...
 public Region(int id, String name, double funds, double secFactor, Requirement... someRequirements){
        allRegions.add(this);
        this.id = id;
        this.funds = funds;
        this.name = name;
        this.securityFactor = secFactor;
        for(Requirement r : someRequirements){
            this.requirements.add(r);
        }        
    }
```
Dieser Konstruktor added diese zu einer ArrayList, welche dann später in dem static-block der Database.java  in die Datenbank abgepeichert wird.(bzw. sollte).


```
@Entity
@SequenceGenerator(name="req_id", sequenceName="req_id_seq")
public class Requirement implements Serializable{

    @Id
    @GeneratedValue(generator="req_id", strategy=GenerationType.AUTO)
    int id = -61;     //Das ist nur zum Schauen ob überhaupt IDs generiert werden

    @ManyToOne
    Region region;
    
    @OneToOne
    Subject subject;
    
    @Column(name="clevel")
    int level = 0;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }


    public int getLevel() {
        return level;
    }

    public void setLevel(int level) {
        this.level = level;
    }

    public Subject getSubject() {
        return subject;
    }

    public void setSubject(Subject subject) {
        this.subject = subject;
    }



    public Requirement() {
    }

    public Requirement(Subject anSubject, int level){
        this.subject = anSubject;
        this.level = level;
    }

    @Override
    public String toString() {
           return subject.toString()+" "+level;
    }


}
```


```
@Entity
public class Subject implements Serializable {

    @Transient
    public static ArrayList<Subject> allSubjects = new ArrayList<Subject>();

    @Id
    int id = -64;
    
    private String name;
    "Wirtschaft","Biologie","Erdkunde","Italienisch","Spanisch","Geschichte","Informatik"};

    public static Subject MATH = new Subject(1, "Mathe");
    public static Subject GERMAN = new Subject(2, "Deutsch");
    public static Subject FRENCH = new Subject(3, "Französisch");
    public static Subject ENGLISH = new Subject(4, "Englisch");
    public static Subject SPORT = new Subject(5, "Sport");


   public Subject () {
    }

   public Subject(int id, String name) {
       this.id = id;
        this.name = name;        
        allSubjects.add(this);
    }
```

Vielleicht ums ein bisschen verständlicher zu machen.

```
Player n:1 -> Region 1:n -> Requirement m:1 -> Subject
```


----------



## SlaterB (27. Mai 2009)

> @OneToOne
>    Subject subject;

hast du nicht vielleicht doch mehrere Requirements mit demselben Subject?
bzw. m:1 sagt es ja schon, also ManyToOne,

was genau ist die Integritätsbedingung 'FK7912842313767E40', hast du einen Blick auf die Datenbank und Kenntnis zur Interpretation?
wie wurde die DB angelegt/ gibts ein Skript?


----------



## KlinCh (27. Mai 2009)

SlaterB hat gesagt.:


> > @OneToOne
> >    Subject subject;
> 
> hast du nicht vielleicht doch mehrere Requirements mit demselben Subject?
> bzw. m:1 sagt es ja schon, also ManyToOne,


Stimmt, das ist zumindest schonmal ein Fehler, ich habe ihn gefixt, doch das Problem besteht weiterhin.


> was genau ist die Integritätsbedingung 'FK7912842313767E40', hast du einen Blick auf die Datenbank und Kenntnis zur Interpretation?
> wie wurde die DB angelegt/ gibts ein Skript?



Also ehrlich gesagt ich weiss nicht mal so ganz genau was eine Integritätsbedingung ist, dem Wortlaut nach würde ich Vermuten es ist irgendeine Regel, nach der nur "passende", "sich integrierende" daten eingefügt können.

Wie kann/könnte ich diese Abfragen?
Ich könnte die komplette DB dumpen, hilft dir das?

Also die Datenbank ist eine vanilla javadb, angelegt aus dem kontextmenü von netbeans.
Die ganzen Tabellen werden von Hibernate selbst angelegt:
hibernate.
[XML]<hibernate-configuration>
  <session-factory>
    <property name="hibernate.dialect">org.hibernate.dialect.DerbyDialect</property>
    <property name="hibernate.connection.driver_class">org.apache.derby.jdbc.ClientDriver</property>
    <property name="hibernate.connection.url">jdbc:derby://localhost:1527/myschool</property>   
    <property name="hibernate.current_session_context_class">thread</property>
* <property name="hibernate.hbm2ddl.auto">update</property>*
...
   [/XML]


----------



## SlaterB (27. Mai 2009)

naja, da wollen wir mal lieber nicht weiter nachforschen, ManyToOne schon ausprobiert?

als nächstes würde ich dir detaillertes save() vorschlagen, also Arbeit:
speichere zunächst alle Subjekte + commt, klappts oder Exception?
dann alle Regionen, damit dürfte es doch spätestens zu einer Exception beim Commit kommen?
dann nur eine der Regionen, dann 2, dann 3, wann genau ist die minimale Konstellation erreicht?
dann in der letzten Region die enthaltenen Objekte, die Probleme machen könnten, einzeln entfernen bzw. die Objekte in den Objekten usw.


----------



## KlinCh (27. Mai 2009)

Also Abspeichern eines einzelnen Subjects reicht schon für eine Exception.


```
SCHWERWIEGEND: Die Anweisung wurde abgebrochen, weil sie in einer für 'SUBJECT' definierten Vorgabe für einen eindeutigen oder Primärschlüssel bzw. für einen von 'SQL090527223012440' bezeichneten eindeutigen Index zu einem duplizierten Schlüsselwert geführt hätte.
...
```

eigentlich klarer Fall, aber ich hatte die Datenbank vorher extra gelöscht und neu angelegt um eben dies auszuschließen; dann aber ist mir aufgefallen ,dass das initialize() zweimal aufgerufen wird.(für mich ein Mysterium) und hab das .save zu .saveOrUpdate geändert. und es funktionierte.

-> Danach(also eigentlich schon kurz bevor) fiel mir auf, dass ich beim ursprünglichen Code nur ein .update(s) stehen hatte und das im Zusammenhang mit dem zweimaligen Aufrufen von initialize() war wohl der Fehler.

Jetzt frag ich mich aber noch wieso initialize() zweimal aufgerufen wird.
Testanordnung:
eine Datei Test.java: die ich immer starte zum Testen

```
public class Test {
    public static void main(String[] args){
        Database.initialize();     
    }
}
```
+nochmal die Database.java:

```
public class Database {

    static boolean isInitializised = false;
    
    static {
        if(isInitializised == false){
            initialize();
        }
    }
    public static void initialize(){
        Logger logger = Logger.getLogger(Database.class.getName());
        logger.log(Level.INFO, "Initializising Database");
        isInitializised = true;
        Session session = InitHibernate.getSessionFactory().getCurrentSession();
        session.beginTransaction();
        try{
            /* Läd alle Fächer in die Datenbank */
            logger.log(Level.INFO, "Loading all Subjects into DB");
            for(Subject s : Subject.allSubjects){
                logger.log(Level.INFO, "saveOrUpdate Subject :"+s.toString()+", ID: "+s.getId());
               session.saveOrUpdate(s);

           }

            /* Läd alle Regionen in die Datenbank */
            logger.log(Level.INFO, "Loading all Regions into DB");
            for(Region r : Region.allRegions){
                session.saveOrUpdate(r);
                logger.log(Level.INFO, "saveOrUpdate Region :"+r.toString()+", ID: "+r.getId());
            }
            /* Läd alle ChaosEvents in die Datenbank */
            logger.log(Level.INFO, "Loading all ChaosEvetns into DB");
            for(ChaosEvent ce : ChaosEvent.allChaosEvents){
                session.saveOrUpdate(ce);
                logger.log(Level.INFO, "saveOrUpdate ChaosEvent :"+ce.toString()+", ID: "+ce.getId());
            }

//            session.saveOrUpdate(Subject.ENGLISH);
            

            session.getTransaction().commit();
            logger.log(Level.INFO, "Initializising Database: successfull");

        } catch(HibernateException ex){
            session.getTransaction().rollback();
            ex.printStackTrace();
            logger.log(Level.WARNING, "Initializising Database: error");
        }
    }
```


----------



## ck2003 (28. Mai 2009)

KlinCh hat gesagt.:


> ...
> eigentlich klarer Fall, aber ich hatte die Datenbank vorher extra gelöscht und neu angelegt um eben dies auszuschließen; dann aber ist mir aufgefallen ,dass das initialize() zweimal aufgerufen wird.(für mich ein Mysterium) und hab das .save zu .saveOrUpdate geändert. und es funktionierte.
> 
> -> Danach(also eigentlich schon kurz bevor) fiel mir auf, dass ich beim ursprünglichen Code nur ein .update(s) stehen hatte und das im Zusammenhang mit dem zweimaligen Aufrufen von initialize() war wohl der Fehler.
> ...



Kurz und knapp: weil du es zweimal aufrufst. Zuerst im statischen Block in Database und dann in deiner Test-Klasse.


----------



## KlinCh (28. Mai 2009)

Stimmt, das mit dem isInitialied ist so wie es war, natürlich schwachsinn; kann spät abends schonmal passieren ;-)

Momentan scheint alles zu funktionieren.
Vielen Dank dir und SlaterB


----------

