Jpa OneToMany perzisztálási hiba

Fórumok

Hozzászólások

Ha egy vevőnek több gépkocsija is lehet, akkor inkább ManyToMany kapcsolat kellene. Ez mondjuk nem változtat a kapcsolótábla mappelésén...

A mysql melyik constraint-en száll el? (ha jól sejtem, korrelál a második hibaüzenettel)

A Vevo entitás a VEVOCIM táblára van mappelve, vagy ez két külön dolog?

A Vevo entitás ID mappelése pedig nem tűnik jónak, az idmod field nem az IDMOD oszlopra kellene mutasson?

- A vevo entitasnak ket @Id mezoje van. Ez nem biztos, hogy baj, ha megosztott kulcsot akarsz, de itt szerintem nem ez a helyzet.
- Az id generalasa hogy tortenik? Ebbol ugy tunik, sehogy sem autoincrement, sem "kezi" megadas nem latszik. Ez alapjan neked kell feltoltened. Mivel nem mondtal nullable=false-t, az id-hez ezert a jpa nem fogja ellenorizni es megengedi null id-ju rekordok beszurasat. A join-nal unique=true van. Ezert a masodik hivatkozo rekord beszurasanal hibat fog generalni.

Igen, a vevő entitásnak szándékosan van 2 @Id-je tehát a primary key 2 mezőből áll.
Az id-t én generálom mikor a vevő entitás először kerül mentésre. A "masodik hivatkozo rekord" beszúrásának elvileg meg sem kellene történnie mert már létezik.

A folyamat a következő képen kellene hogy kinézzen:

1. Valamikor a múltban keletkeztek vevő entitások, melyek perzisztálva is lettek.

2. Keletkezik egy új

Gepkocsi

entitás, mely

List<Vevocim> vevocimek;

listájához hozzá szeretnék adni

entity.getVevocimek().add(cim)

egy vevőcímet mely ekkor már létezik.
Tehát azt szeretném, hogy perzisztáláskor elmentse mind a

Gepkocsi

entitást a

GEPKOCSI

táblába, mind pedig a megfelelő iserteket beszúrja a

GEPKOCSI_VEVOCIM_OSSZERENDELO

táblába ami összerendeli a gépkocsit a vevő címekkel. Na ez nem történik meg,

Cannot add or update a child row: a foreign key constraint fails

hibával elszáll mert valószínűleg a MySQL még nem látja a

GEPKOCSI

táblában a rekordot és mivel egy foreign key constrait van rajta dob egy hátast.

Viszont ha a folyamat úgy történik, hogy először létrehozok egy a gépkocsi entitást, kitöltöm minden mezőjét, de nem adok a vevőcím listához egyetlen rekordot sem, kiadok egy persist utasítást, akkor elmenti, majd ehhez a mentett entitáshoz adok vevő címeket és újra elmentem, akkor már nem ad ilyen hibát, mert létezik adatbázis szinten is a

GEPKOCSI

táblában a rekord így a

GEPKOCSI_VEVOCIM_OSSZERENDELO

tábla constraintjei nem sérülnek.

A kérdés, hogy fel lehet e úgy annotálni ezt a Gepkocsi osztályt, hogy először mentse el magát a Gépkocsi osztályt és ha ez megtörtént csak utána perzisztálja a

@OneToMany private List<Vevocim> vevocimek;

kapcsolatot.
Vagy a JPA ezt nem tudja lekezleni és keressek más megoldást?

Hát ha nagyon muszáj akkor lehet. Mivel OneToMany kapcsolatról van szó, így a VEVOCIM táblába be lehet tenni egy ID_GEPKOCSI mezőt és akkor ki lehet hagyni a kapcsoló táblát.
Viszont ez egy kiegészítő modul, ami csak egy ügyfélnek kell, így lehet szerencsésebb a külön tábla, és az elején még ment a variálás, hogy egy címet csak egy gépkocsihoz lehessen rendelni vagy akár tömbhöz is, és megvan az esélye annak hogy előbb utóbb ManyToMany kapcsolat lesz ebből és lehet így fájdalommentesebb lesz a módosítás ha egyből kapcsoló táblával oldjuk meg.

A frontend JSF. A vevő egy PrimeFaces autocomplet komponenssel kerül kiválasztásra.

A folyamat úgy néz ki, hogy rábök az új gépkocsi hozzáadása gombra, akkor megjelenik egy JSF page ahol ki tudja tölteni a rendszámot, forgalmi engedély számot, stb.
Ekkor a backend rétegben létrejön egy gépkocsi objektum.
Gepkocsi gepkocsi = new Gepkocsi();
A JSF oldal mezői ennek az objektumnak a megfelelő mezőire vannak állítva. A vevők már léteznek, lehet hónapokkal ezelőtt vitték fel őket és egy autocomplett komponens segítségével kerülnek kiválasztásra és a gepkocsi entitás vevocimek listájához vannak hozzáadva entity.getVevocimek().add(cim).

Az insertek a háttérben nem tudom milyen sorrendben mennek le.
Nekem az ideális az lenne ha először a GEPKOCSI tábla insertje futna le aztán a GEPKOCSI_VEVOCIM_OSSZERENDELO tábláé. A VEVOCIM táblába meg nem kellene insertálnia mert a vevőcím létezik és nem is módosul.
De most vagy az van, hogy előbb a GEPKOCSI_VEVOCIM_OSSZERENDELO táblába akar először insertálni aztán a GEPKOCSIBA, vagy A GEPKOCSIBA insertál utána a GEPKOCSI_VEVOCIM_OSSZERENDELO táblába csak akkor ezt nem értem ha egy tranzakción belül van a két insert akkor a GEPKOCSI_VEVOCIM_OSSZERENDELObe történő insertáláskor miért száll el hogy nem létezik a gépkocsiba az az ID?

személy szerint gyűlölöm a JPA-t, de nem valami detached/attached magic lesz itt a háttérben?

hogy mikor kikerült a felületre a `cím` entitás, a JPA elveszít minden róla szóló infót - s a mentéskor nem tudja, hogy ez egy új entitás (amit tényleg insertelni kell), vagy egy meglévő...

Esetleg ennek a legalja alapján kipróbálnám az `em.merge(entity)` hívást.
De ez már tényleg a JPA olyan mélysége, amit, hacsak lehet, kerülök, sry.

--
blogom

Na sikerült megtalálni mi a hiba.
Bekapcsoltam a logolást, hogy minden SQL utasítás írjon ki.
Abból láttam, hogy mikor a GEPKOCSI_VEVOCIM_OSSZERENDELO táblába insertál akkor a gépkocsi id-je 0, amit ugye az adatbázis kezelő (MySql) oszt, és mivel nem volt beállítva a gépkocsi entitás id mezőjére a @GeneratedValue(strategy=GenerationType.IDENTITY) annotácio így a child rekord inzertálásakor a gépkocsi entitás még nem kapta vissza az adatbázis által neki kiosztott azonosítót. De az annotáció megoldotta a problémát és így már szépen működik.