Potřebuji poradit s jednou pro vás nejspíš triviální věcí.
Snažím se naučit, jak se pracuje s persistencí a s JPA ale stále v tom tápu, bo
angličtina není zrovna moje hobby a nejspíš hodně občas nedokážu anglické
manuály správně přeložit.
Používám NetBeans .
Mám desktop aplikaci, s databází MySQL a JDBC balíček, toplink a
org.jdesktop.beansbinding (ty jsou dodané v NetBeans).
Mám dvě tabulky
CREATE TABLE `klienti` (
`klic` int(11) NOT NULL auto_increment,
`pr_naz` varchar(50) ,
...
PRIMARY KEY (`klic`),
KEY `pr_naz` (`pr_naz`),
KEY `typ` USING BTREE (`typkl`)
)
CREATE TABLE `adresar` (
`klic` int(11) NOT NULL auto_increment,
`klienti_klic` int(11) NOT NULL default '0',
`jm` varchar(18) ,
`pr_naz` varchar(50) ,
...
ulice,telefony atd ...
....
PRIMARY KEY (`klic`),
KEY `pr_naz` (`pr_naz`),
KEY `klienti_klic` USING BTREE (`klienti_klic`),
CONSTRAINT `FK_adresar_klienti` FOREIGN KEY (`klienti_klic`) REFERENCES
`klienti` (`klic`)
)
Relace je klienti:adresar je 1:n
NetBeans mi podle cizího klíče vygeneroval entity:
@Entity
@Table(name = "klienti")
@NamedQueries(
{
@NamedQuery(name = "Klienti.findByKlic", query = "SELECT k FROM Klienti k
WHERE k.klic = :klic"),
@NamedQuery(name = "Klienti.findByPrNaz", query = "SELECT k FROM Klienti k
WHERE k.prNaz = :prNaz"),
...
})
public class Klienti implements Serializable {
@Id
@Column(name = "klic",updatable=false, nullable = false)
private Long klic;
@Column(name = "pr_naz", nullable = false)
private String prNaz;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "klienti")
@JoinColumn(name="klienti_klic")
private Collection<Adresar> adresarCollection;
public Klienti() { }
public Long getKlic() { return klic; }
public void setKlic(Long klic) { this.klic = klic; }
public String getPrNaz() { return prNaz; }
public void setPrNaz(String prNaz) { this.prNaz = prNaz; }
public Collection<Adresar> getAdresarCollection() { return
adresarCollection; }
public void setAdresarCollection(Collection<Adresar> adresarCollection) {
this.adresarCollection = adresarCollection;
}
public void addAdresar(Adresar adr) {
adr.setKlienti(this);
this.adresarCollection.add(adr);
}
public Adresar newAdresar() {
Adresar adresar;
adresar = new Adresar();
entityManager.persist(adresar);
addAdresar(adresar);
return adresar;
}
@Override
public int hashCode() ....
@Override
public boolean equals(Object object) ...
@Override
public String toString() ...
}
@Entity
@Table(name = "adresar")
@NamedQueries(
{
@NamedQuery(name = "Adresar.findByKlic", query = "SELECT a FROM Adresar a
WHERE a.klic = :klic"),
@NamedQuery(name = "Adresar.findByPrNaz", query = "SELECT a FROM Adresar a
WHERE a.prNaz = :prNaz"),
...
})
public class Adresar implements Serializable, InterfaceAdresar
{
@Id
@Column(name = "klic", nullable = false)
private Integer klic;
@Column(name = "pr_naz", nullable = true)
private String prNaz;
@JoinColumn(name = "klienti_klic", referencedColumnName = "klic")
@ManyToOne
private Klienti klienti;
public Adresar()
{
}
public Integer getKlic() { return klic; }
public void setKlic(Integer klic) { this.klic = klic; }
public String getPrNaz() { return prNaz; }
public void setPrNaz(String prNaz) { this.prNaz = prNaz; }
@Override
public int hashCode() { ... }
@Override
public boolean equals(Object object) { ... }
@Override
public String toString() { ... }
public Klienti getKlienti()
{ return klienti; }
public void setKlienti(Klienti klienti)
{ Klienti oldKlienti = this.klienti;
this.klienti = klienti;
changeSupport.firePropertyChange("klienti", oldKlienti, klienti);
}
}
používám systém tak jak to vygeneruje NetBeans s tím,
že se transakce otevře v konstruktoru formuláře
entityManager.getTransaction().begin();
nový klient do formuláře se získá:
cz.ahsw.klienti.entity.Klienti kli = new
cz.ahsw.klienti.entity.Klienti();
entityManager.persist(k);
a pro novou adresu k němu se využije metoda Adresar.newAdresar()
tj.
Adresar adr = kli.newAdresar();
Uloží se
private void saveButtonActionPerformed(java.awt.event.ActionEvent evt) {
entityManager.getTransaction().commit();
entityManager.getTransaction().begin();
}
Update funguje
Přidávat nové adresy ke klientovi, který je již v předešlém kroku uložen
v databázi jde též bez chyby.
Ovšem při pokusu založit klienta i jeho adresu zároveň nelze.
Nepřenese se do adresy klíč klienta a insert zkončí na tom,
že databáze zabrání vložení null hodnoty.
Call: INSERT INTO adresar (klic, tel, mobil_fax, pr_naz, email, cp, ins_kdy,
jm, ins_kdo, mesto, uli, klienti_klic) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
?)
bind => [null, null, null, null, null, null, null, null, 0, iojuoiuoi,
kljkljl, null]
Query:
InsertObjectQuery(cz.ahsw.klienti.entity.Adresar[klic=null];null,null,kljkljl,null,null)
Exception in thread "AWT-EventQueue-0" javax.persistence.RollbackException:
Exception [TOPLINK-4002] (Oracle TopLink Essentials - 2.0 (Build b58g-fcs
(09/07/2007))): oracle.toplink.essentials.exceptions.DatabaseException
Internal Exception:
com.mysql.jdbc.exceptions.MySQLIntegrityConstraintViolationException: Column
'klienti_klic' cannot be null
Error Code: 1048
Kde je problém, že se ten nový klíč nepřenese do instance adresar, kterou má v
kontejneru
a měl by je též insertovat?
Může mi s tím někdo poradit?
Může mě někdo orientovat na nějaký dobře napsaný a pochopitelný tutoriál,
nejlépe v češtině?
Jsem s JPA naprosto na začátku. Trošku mě zklamal. Jsem zvyklý psát v SQL (ISO)
– je to trochu víc práce, ale funguje to jak předpokládám.
Tyhle persistence jsou černá skřínka a co z toho vyleze zatím netuším. Zatím mi
studium a hledání informací po internetu zabralo příliš mnoho času a netuším,
zda se efektivita zvedne oproti míře vynaloženého úsilí natolik, aby se mi to
vyplatilo to toho JPA jít…
Díky mnohokrát za rady :-)!
Arnošt