Na początek: brak kaskadowości, mapowanie jednostronne.
Mapowania i klasy POJO:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="main">
<class name="Produkt" table="produkt">
<id name="id" unsaved-value="null" column="produkt_id">
<generator class="sequence">
<param name="sequence">prod_seq</param>
</generator>
</id>
<property name="name" />
<property name="value" />
</class>
</hibernate-mapping>
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="main">
<class name="Kategoria" table="kategoria">
<id name="id" unsaved-value="null" column="kategory_id">
<generator class="sequence">
<param name="sequence">kat_seq</param>
</generator>
</id>
<property name="name" />
<property name="type" />
<property name="description" />
<set name="products" lazy="true" inverse="false" cascade="none">
<key column="kategory_id" />
<one-to-many class="Produkt" />
</set>
</class>
</hibernate-mapping>
package main;
public class Produkt {
Integer id;
String name;
Integer value;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getValue() {
return value;
}
public void setValue(Integer value) {
this.value = value;
}
}
package main;
import java.util.HashSet;
import java.util.Set;
public class Kategoria {
Integer id;
String name;
String type;
String description;
Set<Produkt> products = new HashSet<Produkt>();
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Set<Produkt> getProducts() {
return products;
}
public void setProducts(Set<Produkt> products) {
this.products = products;
}
}
Zapisanie do bazy danych kategorii i produktu wygląda następująco:
package main;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class Main {
public static void main(String[] args) {
Session session = null;
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
session = sessionFactory.openSession();
Kategoria kat = new Kategoria();
Produkt prod1 = new Produkt();
Produkt prod2 = new Produkt();
kat.setName("kat");
prod1.setName("prod1");
prod2.setName("prod2");
kat.getProducts().add(prod1);
kat.getProducts().add(prod2);
session.beginTransaction();
session.save(prod1);
session.save(prod2);
session.save(kat);
session.flush();
session.getTransaction().commit();
session.close();
System.out.println("zapisane!");
session = sessionFactory.openSession();
session.beginTransaction();
System.out.println("Kategorie: "+session.createQuery("from Kategoria").list().size());
System.out.println("Produkty: "+session.createQuery("from Produkt").list().size());
session.clear();
session.delete(prod1);
session.flush();
session.getTransaction().commit();
session.close();
System.out.println("produkt usuniety");
session = sessionFactory.openSession();
session.beginTransaction();
System.out.println("Kategorie: "+session.createQuery("from Kategoria").list().size());
System.out.println("Produkty: "+session.createQuery("from Produkt").list().size());
session.clear();
session.delete(kat);
session.flush();
session.getTransaction().commit();
session.close();
System.out.println("kategoria usunieta");
session = sessionFactory.openSession();
session.beginTransaction();
System.out.println("Kategorie: "+session.createQuery("from Kategoria").list().size());
System.out.println("Produkty: "+session.createQuery("from Produkt").list().size());
System.out.println("end");
}
}
Bardzo ważne jest, aby zapisać zarówno produkt jak i kategorię. Jeśli tego nie zrobimy, pojawi się błąd: exception in thread "main" org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: main.Produkt. Kolejność zapisywania nie jest istotna.
W kodzie musiałem wyczyścić sesję (session.clear()), żeby uniknąć błędu: org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session.
Wynikiem działania programiku jest:
zapisane!
Kategorie: 1
Produkty: 2
produkt usuniety
Kategorie: 1
Produkty: 1
kategoria usunieta
Kategorie: 0
Produkty: 1
end
Niby ok, ale dlaczego istnieje produkt bez kategorii? Jeśli spojrzymy do bazy danych, to faktycznie zobaczymy, że w tabeli Produkty istnieje wpis "prod2" z pustą wartością klucza obcego kategory_id. Trochę to nieintuicyjne. Może można zrobić tak, że obiekty zależne (produkty) zapisywane i usuwane są razem z obiektem nadrzędnym (kategorią)? Oczywiście, że można. Trzeba się tylko trochę namęczyć:
Mapowania:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="main">
<class name="Kategoria" table="kategoria">
<id name="id" unsaved-value="null" column="kategory_id">
<generator class="sequence">
<param name="sequence">kat_seq</param>
</generator>
</id>
<property name="name" />
<property name="type" />
<property name="description" />
<set name="products" lazy="true" inverse="true" cascade="all">
<key column="kategory_id" />
<one-to-many class="Produkt"/>
</set>
</class>
</hibernate-mapping>
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="main">
<class name="Produkt" table="produkt">
<id name="id" unsaved-value="null" column="produkt_id">
<generator class="sequence">
<param name="sequence">prod_seq</param>
</generator>
</id>
<property name="name" />
<property name="value" />
<many-to-one name="kategoria" class="Kategoria" not-null="true" column="kategory_id"/>
</class>
</hibernate-mapping>
Klasy POJO:
package main;
import java.util.HashSet;
import java.util.Set;
public class Kategoria {
Integer id;
String name;
String type;
String description;
Set<Produkt> products = new HashSet<Produkt>();
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Set<Produkt> getProducts() {
return products;
}
public void setProducts(Set<Produkt> products) {
this.products = products;
}
public void addProduct(Produkt product) {
if (product.getKategoria()==null)
product.setKategoria(this);
products.add(product);
}
}
package main;
public class Produkt {
Integer id;
String name;
Integer value;
Kategoria kategoria;
public Kategoria getKategoria() {
return kategoria;
}
public void setKategoria(Kategoria kategoria) {
this.kategoria=kategoria;
this.kategoria.getProducts().add(this);
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getValue() {
return value;
}
public void setValue(Integer value) {
this.value = value;
}
}
W mapowaniach i POJO kluczowe są opcje "cascade", "inverse" oraz settery (setKatgoria, setProdukt, addProdukt) - bez nich nie proste operacje na javovych obiektach nie miałyby bezpośredniego przełożenia na sytuację w bazie danych.
No i main:
package main;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class Main {
public static void main(String[] args) {
Session session = null;
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
session = sessionFactory.openSession();
session.beginTransaction();
Kategoria kat = new Kategoria();
Produkt prod1 = new Produkt();
Produkt prod2 = new Produkt();
prod1.setName("prod1");
prod2.setName("prod2");
kat.addProduct(prod1);
prod2.setKategoria(kat);
session.save(kat);
session.flush();
session.getTransaction().commit();
session.close();
System.out.println("zapisane!");
session = sessionFactory.openSession();
session.beginTransaction();
System.out.println("Kategorie: "+session.createQuery("from Kategoria").list().size());
System.out.println("Produkty: "+session.createQuery("from Produkt").list().size());
session.clear();
session.delete(prod1);
kat.getProducts().remove(prod1);
session.flush();
session.getTransaction().commit();
session.close();
System.out.println("produkt usuniety");
session = sessionFactory.openSession();
session.beginTransaction();
System.out.println("Kategorie: "+session.createQuery("from Kategoria").list().size());
System.out.println("Produkty: "+session.createQuery("from Produkt").list().size());
session.clear();
System.out.println("produkty: "+kat.getProducts().size());
session.delete(kat);
session.flush();
session.getTransaction().commit();
session.close();
System.out.println("kategoria usunieta");
session = sessionFactory.openSession();
session.beginTransaction();
System.out.println("Kategorie: "+session.createQuery("from Kategoria").list().size());
System.out.println("Produkty: "+session.createQuery("from Produkt").list().size());
System.out.println("end");
}
}
Wynik działania programu:
zapisane!
Kategorie: 1
Produkty: 2
produkt usuniety
Kategorie: 1
Produkty: 1
produkty: 1
kategoria usunieta
Kategorie: 0
Produkty: 0
end

Brak komentarzy:
Prześlij komentarz