0

Today I did some experiments with hibernate. First of all there is no deeper sense behind my program. I just wanted to try the framework. I planed the following db tables:

  • Car (Auto)
  • Driver (Fahrer)
  • Wohnung (Flat)
  • Guest (Fahrgast)

with the following bidirectional mappings:

  • driver – flat onetoone
  • driver – car onetomany
  • car – guest manytomany

After preparing the single classes I wrote my worker to insert some demodata. Up to this point everything works as expected. Finally I would like to remove one of my drivers. But hibernate tells me, that it would be re-saved by a certain guest. Unfortunately I don’t understand why. I expected everything to be fine after removing the driver from the driver collection of the corresponding cars.

class car

package mycode;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;

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

@Entity
@Table(name="auto")
public class Auto {

@Id @GeneratedValue
private int id;
@Column(name="nummernschild", nullable = false)
private String nummernschild;
@OneToMany(cascade=CascadeType.ALL, mappedBy="auto")
private List<Fahrer>fahrers = new ArrayList<Fahrer>();
@ManyToMany(cascade=CascadeType.ALL)
private List<Fahrgast>fahrgasts = new ArrayList<Fahrgast>();

public List<Fahrgast> getFahrgasts() {
    return fahrgasts;
}
public void setFahrgasts(List<Fahrgast> fahrgasts) {
    this.fahrgasts = fahrgasts;
}
public List<Fahrer> getFahrers() {
    return fahrers;
}
public void setFahrers(List<Fahrer> fahrers) {
    this.fahrers = fahrers;
}
private LocalDate kaufdatum;
public LocalDate getKaufdatum() {
    return kaufdatum;
}
public void setKaufdatum(LocalDate kaufdatum) {
    this.kaufdatum = kaufdatum;
}
public int getId() {
    return id;
}
public void setId(int id) {
    this.id = id;
}
public String getNummernschild() {
    return nummernschild;
}
public void setNummernschild(String nummernschild) {
    this.nummernschild = nummernschild;
}

}

class driver

package mycode;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.persistence.Table;

@Entity
@Table(name="fahrer")
public class Fahrer {
@Id @GeneratedValue()
private int id;
private String vorname, nachname;
private int alter;

@OneToOne (cascade=CascadeType.ALL)
@JoinColumn(name="id")
private Wohnung wohnung;
@ManyToOne(cascade=CascadeType.ALL)
private Auto auto;


public Auto getAuto() {
    return auto;
}
public void setAuto(Auto auto) {
    this.auto = auto;
}
public Wohnung getWohnung() {
    return wohnung;
}
public void setWohnung(Wohnung wohnung) {
    this.wohnung = wohnung;
}

public int getId() {
    return id;
}
public void setId(int id) {
    this.id = id;
}
public String getVorname() {
    return vorname;
}
public void setVorname(String vorname) {
    this.vorname = vorname;
}
public String getNachname() {
    return nachname;
}
public void setNachname(String nachname) {
    this.nachname = nachname;
}
public int getAlter() {
    return alter;
}
public void setAlter(int alter) {
    this.alter = alter;
}

}

class flat

package mycode;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;

import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter;

@Entity
@Table(name="wohnung")
public class Wohnung {
    @Id @GeneratedValue(generator = "newGenerator")
    @GenericGenerator(name="newGenerator", strategy="foreign" , parameters= {@Parameter(value="fahrer", name="property")})
private int id; 
@Column(nullable=false)
private String ort, straße;
@OneToOne(cascade=CascadeType.ALL)
@JoinColumn(name="id")
private Fahrer fahrer;
public int getId() {
    return id;
}
public void setId(int id) {
    this.id = id;
}
public String getOrt() {
    return ort;
}
public void setOrt(String ort) {
    this.ort = ort;
}
public String getStraße() {
    return straße;
}
public void setStraße(String straße) {
    this.straße = straße;
}
public Fahrer getFahrer() {
    return fahrer;
}
public void setFahrer(Fahrer fahrer) {
    this.fahrer = fahrer;
}


}

class guest

package mycode;

import java.util.ArrayList;
import java.util.List;

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

@Entity
@Table(name="fahrgast")
public class Fahrgast {
@Id @GeneratedValue
private int id;
@Column(nullable=false)
private int kundennummmer;
private String vornname, nachname;
@ManyToMany(mappedBy="fahrgasts")
private List<Auto>autos = new ArrayList<Auto>();

public List<Auto> getAutos() {
    return autos;
}
public void setAutos(List<Auto> autos) {
    this.autos = autos;
}
public int getId() {
    return id;
}
public void setId(int id) {
    this.id = id;
}
public int getKundennummmer() {
    return kundennummmer;
}
public void setKundennummmer(int kundennummmer) {
    this.kundennummmer = kundennummmer;
}
public String getVornname() {
    return vornname;
}
public void setVornname(String vornname) {
    this.vornname = vornname;
}
public String getNachname() {
    return nachname;
}
public void setNachname(String nachname) {
    this.nachname = nachname;
}


}

class worker

package mycode;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;

public class Worker {

    private Session session;
    private SessionFactory sf;
    public static void main(String[] args) {

        Worker worker = new Worker();
        worker.work();
    }

    private void init()
    {
        Configuration configuration = new Configuration().configure();

        sf = configuration.buildSessionFactory();
        session = sf.openSession();

    }

    private void work()
    {
        init();
        Auto auto = new Auto(); 
        auto.setNummernschild("HH:MK:"+1);
        LocalDate ld = LocalDate.now();
        auto.setKaufdatum(ld);

        session.beginTransaction();
        for (int i=0; i<10; i++)
        {


            auto = new Auto();
            auto.setNummernschild("HH:MK:"+i);
            ld = LocalDate.now();
            auto.setKaufdatum(ld);

            Auto auto2 = new Auto();

            auto2.setNummernschild("HH:MK:"+i);
            ld = LocalDate.now();
            auto2.setKaufdatum(ld);

            //auto.setId(i);

            Fahrer fahrer = new Fahrer(); 
            fahrer.setVorname("Hans");
            fahrer.setNachname("Huber");
            Fahrer fahrer2 = new Fahrer(); 
            fahrer2.setVorname("Anna");
            fahrer2.setNachname("Schmidt");
            double temp = Math.random();
            int alter = (int)(temp*50);
            fahrer.setAlter(alter);

            fahrer2.setAlter(alter);

            fahrer.setAuto(auto);
            fahrer2.setAuto(auto2);
            Wohnung wohnung = createWohnung(i);
            wohnung.setFahrer(fahrer);
            fahrer.setWohnung(wohnung);
            Wohnung wohnung2 = createWohnung(i*10);
            fahrer2.setWohnung(wohnung2);
            wohnung2.setFahrer(fahrer2);
            auto.getFahrers().add(fahrer);
            auto2.getFahrers().add(fahrer2);

            double zufall = Math.random()*100;
            int zu = (int)zufall;
            for (int z=0; z<zu; z++)
            {
                Fahrgast fahrgast = new Fahrgast(); 
                fahrgast.setVornname("Hans"+z);
                fahrgast.setNachname("Dampf"+z);
                double kundennummer = Math.random()*10000;
                fahrgast.setKundennummmer((int)kundennummer);
                fahrgast.getAutos().add(auto);
                fahrgast.getAutos().add(auto2);
                auto.getFahrgasts().add(fahrgast);
                auto2.getFahrgasts().add(fahrgast);

            }
//          session.save(fahrer);
//          session.save(fahrer2);
            session.save(auto);
            session.save(auto2);

        }

        Fahrer abfrage = session.get(Fahrer.class, 2);
        List<Fahrer>fahrers = session.createCriteria(Fahrer.class).list();
        List<Fahrer>tobedeletet = new ArrayList<Fahrer>();
        for (Fahrer aktuell : fahrers)
        {
            Auto car = aktuell.getAuto();
            List<Fahrer>cardriver = car.getFahrers();
            Fahrer temp = null;
            for (Fahrer driver: cardriver)
            {
                if (driver.getId()==abfrage.getId())
                {
                    tobedeletet.add(aktuell);
                    temp = driver;

                }
            }
            cardriver.remove(temp);
            session.update(car);
        }


        for (Fahrer aktuell : tobedeletet)
        {
            session.remove(aktuell);
        }


        System.out.println(abfrage.getVorname()+ " "+abfrage.getNachname());


        session.getTransaction().commit();
        session.close();
        sf.close();

    }

    private Wohnung createWohnung(int i)
    {
        Wohnung wohnung = new Wohnung(); 
        wohnung.setOrt("bla"+i);
        wohnung.setStraße("blub"+i);
        return wohnung;
    }

}

finally the configuration file

<?xml version='1.0' encoding='utf-8'?>
<hibernate-configuration>
<session-factory>
    <!-- Database connection settings -->
    <property 
     name="connection.driver_class">org.postgresql.Driver</property>
    <property name="connection.url">jdbc:postgresql://192.168.2.252:5432/test</property>
    <property name="connection.username">postgres</property>
    <property name="connection.password">postgres</property>

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

    <!-- SQL dialect -->
    <property name="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</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.internal.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>
    <mapping class="mycode.Auto"/>
    <mapping class="mycode.Fahrer"/>
    <mapping class="mycode.Wohnung"/>
    <mapping class="mycode.Fahrgast"/>
</session-factory>

Can anybody tell me, how to delete one of my drivers?

The error message: ERROR: HHH000346: Error during managed flush [deleted object would be re-saved by cascade (remove deleted object from associations): [mycode.Fahrgast#3]] Exception in thread "main" javax.persistence.EntityNotFoundException: deleted object would be re-saved by cascade (remove deleted object from associations): [mycode.Fahrgast#3] at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:126) at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:155) at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:162) at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1441) at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:491) at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3201) at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2411) at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:467) at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:146) at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$100(JdbcResourceLocalTransactionCoordinatorImpl.java:38) at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:220) at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:68) at mycode.Worker.work(Worker.java:133) at mycode.Worker.main(Worker.java:19)

Michael Konz
  • 170
  • 15

3 Answers3

1

First things first, hope you know that alter is a reserved word, alter table <table_name>;, so you have to change your column name in Fahrer class:

@Column(name = "_alter") // choose any name you want
private int alter;

After that, why do you need so many bidirectional relationships? And look, you have:

class Fahrer {
    // ...
    @ManyToOne(cascade = CascadeType.ALL)
    private Auto auto;

That means, when you delete a fahrer, the auto is deleted to. Is this realy what you want?

Now look at your code:

// at first you check if the ID is equal to abfrage and add it to list
if (driver.getId() == abfrage.getId()) {
    tobedeletet.add(aktuell);
    temp = driver;
}

// at the end you formed a list tobedeleted witch contains elements with the same ID.

for (Fahrer aktuell : tobedeletet) {
    session.remove(aktuell);
}

To be honest, I'm a java beginner, so I may miss something. But deleting an entity with the same ID value a few times is propably not necessary.

0

Your exception says: remove deleted object from associations

It sould be enough just to remove the fahrer from the Auto#fahrers collection and update auto:

auto.getFahrers().remove(fahrer);
// remove other fahrers
session.update(auto);

Because you have a cascade=CascadeType.ALL property on your auto-to-fahrers relationship in Auto class, after updating the Auto, Fahrer should be deleted automaticly.

More about here: https://stackoverflow.com/a/11649941/6521788

And few things to notice:

  • PLEASE, use one language in your code :). Auto car = aktuell.getAuto();. You get auto, but the variable is called car...

  • PostgreSQLDialect is deprecated, choose PostgreSQL9Dialect or others in your hibernate config;

  • auto is a reserved name, better use something else.

0

Thanks to Oles, I updated my code to

List<Auto>autos = session.createCriteria(Auto.class).list();
        List<Auto>toBeUpdated = new ArrayList<Auto>();
        for (Auto fahzeug : autos)
        {
            List<Fahrer>fahrers2 = fahzeug.getFahrers();
            for (Fahrer aktuell : fahrers2)
            {
                if (aktuell.getId()==abfrage.getId())
                {
                    toBeUpdated.add(fahzeug);
                }
            }

        }
        for (Auto fahrzeug : toBeUpdated)
        {
            fahrzeug.getFahrers().remove(abfrage);
            System.out.println("removed");
            session.update(fahrzeug);
        }

Unfortunately still something doesn’t work as expected. I can’t do the remove inside the fahrerloop, because that ends with a concurrentmodificationexception. With the code posted here, there are no further exceptions. The debugging view shows me, that there are no drivers left for one of the cars after the last loop. Especially the driver with the id 2 gets deleted from the driver list. Unfortunately the driver remains in the database. That shouldn’t be the case, if I understood the last answer correctly.

Michael Konz
  • 170
  • 15