Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[Hibernate]Persist Parent, use generated PK as FK in child

Pagina: 1
Acties:

  • Johan.B
  • Registratie: Maart 2007
  • Laatst online: 18-11 13:41
Ik ben al enige tijd opzoek naar een (waarschijnlijk simpele) oplossing voor volgend probleem:

Ik gebruik Hibernate, Java (Spring) en een MSSQL db.
In de db zitten volgende tabellen:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
+-----------------+
|SurveyEntry      |
+-----------------+
|SurveyEntryID  PK|
|                 |
|some fields      |
+-----------------+

+----------------------+
|SurveyEntryAnswer     |
+----------------------+
|SurveyEntryAnswerID PK|
|SurveyEntryID       FK|
|                      |
|some fields           |
+----------------------+

De primary keys van beide tabellen worden automatisch geïncrementeerd.

Ik wil een surveyentry persisten. In dit surveyentry object zit een set van surveyentryanswers (met surveyentryid null want dit moet nog gegenereerd worden).

surveyentry.hbm.xml
XML:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<hibernate-mapping>
    <class name="....SurveyEntry" table="SurveyEntry">
        <id name="surveyEntryId" type="int">
            <column name="SurveyEntryID" />
            <generator class="increment" />
        </id>
        <set name="surveyEntryAnswers" inverse="true" cascade="persist">
            <key>
                <column name="SurveyEntryID" not-null="true" />
            </key>
            <one-to-many class="....SurveyEntryAnswer" />
        </set>
        
    </class>
</hibernate-mapping>


surveyentryanswer.hbm.xml
XML:
1
2
3
4
5
6
7
8
9
10
11
<hibernate-mapping>
    <class name="....SurveyEntryAnswer" table="SurveyEntryAnswer">
        <id name="surveyEntryAnswerId" type="int">
            <column name="SurveyEntryAnswerID" />
            <generator class="increment" />
        </id>
        <many-to-one name="surveyEntry" class=".....SurveyEntry" fetch="select">
            <column name="SurveyEntryID" not-null="true" />
        </many-to-one>
    </class>
</hibernate-mapping>


Hoe kan ik er voor zorgen dat wanneer Hibernate de surveyentry persist hij het gegenereerde surveyentry id opzoekt en gebruikt als foreign key in de surveyentryanswer objecten?

Java:
1
2
3
4
5
6
7
8
org.hibernate.PropertyValueException: not-null property references a null or transient value: ....SurveyEntryAnswer.surveyEntry
    org.hibernate.engine.Nullability.checkNullability(Nullability.java:72)
    org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:290)
    org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:181)
    org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:121)
    org.hibernate.event.def.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:131)
    org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:87)
    ....

  • Kwistnix
  • Registratie: Juni 2001
  • Laatst online: 13:34
Als het goed is moet een goede cascade strategie hierbij uitkomst bieden.
Jij hebt nu de associatie gemapped met cascade="persist", maar via welke Session methode persisteer je het object?

  • Johan.B
  • Registratie: Maart 2007
  • Laatst online: 18-11 13:41
Java:
1
2
3
HibernateTemplate ht = getHibernateTemplate();
ht.setAlwaysUseNewSession(true);
ht.persist(surveyentry);


Ik maak gebruik van HibernateDaoSupport en Open session in view.
Als .persist() niet goed is, wat moet ik dan wel gebruiken?

[ Voor 7% gewijzigd door Johan.B op 08-05-2008 12:40 ]


  • Sjaaky
  • Registratie: Oktober 2000
  • Laatst online: 06-11 13:54
Zet je bij het toevoegen van een SurveyEntryAnswer aan SurveyEntry.surveyEntryAnswers wel de surveyEntry van SurveyEntryAnswer?

In code zoiets:
Java:
1
2
surveyEntry.surveyEntryAnswers.add(surveyEntryAnswer)
surveyEntryAnswer.setSurveyEntry(surveyEntry);

[ Voor 1% gewijzigd door Sjaaky op 08-05-2008 13:03 . Reden: Even setSurveyEntry() van gemaakt, het blijft natuurlijk java ;) ]


  • Johan.B
  • Registratie: Maart 2007
  • Laatst online: 18-11 13:41
Ik maak een SurveyEntry object en meerdere SurveyEntryAnswer objecten aan. De SurveyEntryAnswer objecten steek ik in een set en deze set steek ik in de SurveyEntry. Ik persist de SurveyEntry.

Zowel de SurveyEntry als de SurveyEntryAnswers hebben nog geen id's. Ik wil dus dat hibernate eerst een SurveyEntry insert en dan het gegenereerde id gebruikt in de SurveyEntryAnswers om die te inserten.

Als ik in elke SurveyEntryAnswer een SurveyEntry zonder SurveyEntryID steek zal hibernate voor elke SurveyEntryAnswer een nieuwe SurveyEntry record aanmaken en dat wil ik natuurlijk niet.

Ik wil dus 1 SurveyEntry record en meerdere SurveyEntryAnswer records met hetzelfde SurveyEntryID

  • Salandur
  • Registratie: Mei 2003
  • Laatst online: 09:25

Salandur

Software Engineer

Wat Sjaaky vraagt is of de SurveyEntryAnswer wel weet wat zijn SurveyEntry is. Hibernate is in dat opzicht redelijk dom en kan niet raden bij welke SurveyEntry een ..Anwser hoort.

Je hoort dus zoiets te hebben:

Java:
1
2
3
4
5
6
7
class Entry {
   Set anwers;
}

class Anwser {
   Entry entry
}

met bijbehoordende setters en getters natuurlijk

[ Voor 33% gewijzigd door Salandur op 08-05-2008 14:08 ]

Assumptions are the mother of all fuck ups | iRacing Profiel


  • Johan.B
  • Registratie: Maart 2007
  • Laatst online: 18-11 13:41
Wel ik ging er van uit dat wanneer een entry een set van answers heeft dat hibernate wel wist dat de answers bij deze entry horen. Blijkbaar is dit niet het geval.

  • Sjaaky
  • Registratie: Oktober 2000
  • Laatst online: 06-11 13:54
Hibernate neemt 1 kant van de associatie als leading. Welke kun je zelf instellen. Standaard is dit de 'one' kant, hibernate kijkt dan naar items in de collection kijkt.

Als je inverse=true instelt, kijkt hibernate naar de 'many' kant, dus het veld surveyEntry in SurveyEntryAnswer.

inverse=true is efficienter in termen van database toegang. De reden daarachter is vast ergens te vinden in de documentatie ;).

  • EfBe
  • Registratie: Januari 2000
  • Niet online
Johan.B schreef op donderdag 08 mei 2008 @ 14:25:
Wel ik ging er van uit dat wanneer een entry een set van answers heeft dat hibernate wel wist dat de answers bij deze entry horen. Blijkbaar is dit niet het geval.
Hibernate en ook nhibernate hebben geen entity graph management voor inmemory graph management. Dit moet je zelf doen.
Dus na
myOrder.Customer = myCustomer;
betekent het niet dat
myCustomer.Orders.Contains(myOrder);
true returned.

Waarom ze dit anno 2008 nog steeds niet hebben ingebouwd is me een raadsel, zo lastig is het nl. niet

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


Verwijderd

EfBe schreef op donderdag 08 mei 2008 @ 15:18:
Dus na
myOrder.Customer = myCustomer;
betekent het niet dat
myCustomer.Orders.Contains(myOrder);
true returned.

Waarom ze dit anno 2008 nog steeds niet hebben ingebouwd is me een raadsel, zo lastig is het nl. niet
Omdat het simpelweg compleet onzinnige functionaliteit is: Klanten plaatsen bestelling, maar bestellingen kiezen geen klant.

  • Orphix
  • Registratie: Februari 2000
  • Niet online
Verwijderd schreef op donderdag 08 mei 2008 @ 15:34:
Omdat het simpelweg compleet onzinnige functionaliteit is: Klanten plaatsen bestelling, maar bestellingen kiezen geen klant.
Semantisch gezien in dit geval wellicht minder relevant. Maar als je een 1:n/m:n relatie in je datamodel hebt mag je verwachten dat na de toewijzing van deze relatie in je code dit voor beide entiteiten geldig is. Bv als je studenten toewijst aan collegezaal (m:1), dan mag je verwachten dat je vanuit de collegezaal geredeneerd alle studenten kan opvragen die aanwezig zijn én dat je voor elke student kan opvragen in welke collegezaal hij of zij aanwezig is.

(Ik heb geen ervaring vader met hibernate dus weet niet of het waar is wat EfBe zegt, maar bovenstaande lijkt me wel wenselijk)

  • EfBe
  • Registratie: Januari 2000
  • Niet online
Verwijderd schreef op donderdag 08 mei 2008 @ 15:34:
[...]
Omdat het simpelweg compleet onzinnige functionaliteit is: Klanten plaatsen bestelling, maar bestellingen kiezen geen klant.
Nee zo onzinnig is die functionaliteit niet. Customer - order is een relatie die je niet bij 1 kant kunt plaatsen. Doe je dat wel, dan kun je in beide entities geen validatie doen op de related entity want je weet niet wanneer die wordt geattached/detached.

Jij plaatst kennelijk de relatie customer - order bij customer. Maar wie zegt dat dat correct is? Immers: de relatie wordt gelegd vanuit order, niet vanuit customer: order is dependent op customer, niet andersom.

(N)Hibernate is de enige mainstream o/r mapper die dit niet heeft, dus onzinnig? Lijkt me niet.

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


Verwijderd

EfBe schreef op donderdag 08 mei 2008 @ 16:50:
Jij plaatst kennelijk de relatie customer - order bij customer. Maar wie zegt dat dat correct is? Immers: de relatie wordt gelegd vanuit order, niet vanuit customer: order is dependent op customer, niet andersom.
Nee, dat zeg ik niet. Ik zeg enkel dat functioneel gezien het aanmaken van een bestelling gedaan wordt door een klant (Klant.doeBestelling). Dat heeft dus helemaal niets te maken met het achterliggende datamodel.

In die zin is het dus onzinnig om in een OO model te kunnen zeggen welke Bestelling bij welke klant hoort. Dat impliceert namelijk dat je in je domein model een Bestelling kan overhevelen naar een andere Klant (zeer uitzonderlijk business model).

  • EfBe
  • Registratie: Januari 2000
  • Niet online
Verwijderd schreef op donderdag 08 mei 2008 @ 17:02:
[...]
Nee, dat zeg ik niet. Ik zeg enkel dat functioneel gezien het aanmaken van een bestelling gedaan wordt door een klant (Klant.doeBestelling). Dat heeft dus helemaal niets te maken met het achterliggende datamodel.

In die zin is het dus onzinnig om in een OO model te kunnen zeggen welke Bestelling bij welke klant hoort. Dat impliceert namelijk dat je in je domein model een Bestelling kan overhevelen naar een andere Klant (zeer uitzonderlijk business model).
De functionaliteit heeft geen moer met semantische interpretatie van de entities te maken. Nu is 'order' wat onzinnig zonder customer wellicht, maar dat hoeft niet. Je kunt bv een systeem hebben waarbij orders aangemaakt worden voordat de customer daadwerkelijk vastgelegd is (zoiets heet bv een purchase order: je levert goederen maar de klant is nog niet fysiek klant, die moet nl. nog betalen etc.). Maar order is niet een goed voorbeeld in deze: het bovenstaande voorbeeld van studenten/collegezaal is beter.

Het punt is dat je kunt navigeren door je graph op de manier die je wilt. Jij kunt wel willen dat je het 'achterliggende' datamodel niet wilt weten, maar die graph management niet beschikbaar hebben is JUIST een reden waarom de achterliggende structuur je wordt opgedrongen: immers je moet nu weten welke kant van een relatie kennelijk de beheerder is van het geheel. Wanneer je dat niet weet, kan het zijn dat je denkt een graph edge toe te voegen maar dat dat niet het geval is. Wat onzinnig is in veel gevallen: de edge is nl. 2-ledig, dat wil je niet gaan babysitten: de developer moet vrij zijn in hoe die edge wordt toegevoegd en dat het altijd werkt.

Dus ook:
myEmployee.WorksForDepartment = myDepartment;
// ... myDepartment.Employees bevat nu myEmployee
// wanneer nu de associatie wordt verlegd naar een ander department:
myEmployee.WorksForDepartment = myDepartment2;
dan moet het dus zijn dat myEmployee UIT myDepartment.Employees wordt gehaald.
En wel met alle notificaties van dien zodat observers weten wat er gaande is en daarnaar kunnen handelen. O/R mapping is meer dan wat entities naar de db sjoelen.

Overigens heeft de afhankelijkheid van order op customer niets te maken met het achterliggende datamodel, maar met het abstracte entitymodel (waar order bv altijd afhankelijk is van customer), en dat is nu net het model waar ook jouw code op gebaseerd is. Althans, als je entity classes op iets anders gebaseerd zijn dan de stand van de zon + de hoek van de wind met het raam.

Dus op het niveau van NIAM/ORM en niet op het niveau van een of ander E/R model

[ Voor 22% gewijzigd door EfBe op 08-05-2008 17:19 ]

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


  • Sjaaky
  • Registratie: Oktober 2000
  • Laatst online: 06-11 13:54
Dat er geen entity graph management niet in hibernate zit is mij eigenlijk ook tegengevallen. Toen we voor hibernate kozen (beetje achter de meute aangelopen...) kende ik de term niet eens. Maar uiteindelijk ben je best nog wel wat plumbing aan het schrijven om te zorgen dat je domein-model op die punten consistent blijft. Zeker om te zorgen dat classes op geen enkele manier fout gebruikt worden door collega's. Want uiteindelijk wil je wel een intuitief te gebruiken domein-model ontwikkelen.

Daarnaast zit je je zeker in het begin nog best wel eens achter het hoofd te krabben waarom iets nu niet wordt opgeslagen in de database. De leercurve was iig steiler dan ik had verwacht. De voorbeelden zien er vaak simpel uit, maar er zijn veel subtiliteiten waar je rekening mee moet houden.

Maar goed, er moet een reden blijven om een ORM te kopen ;).

[ Voor 3% gewijzigd door Sjaaky op 08-05-2008 22:49 ]


Verwijderd

EfBe schreef op donderdag 08 mei 2008 @ 17:12:
De functionaliteit heeft geen moer met semantische interpretatie van de entities te maken. [..]het bovenstaande voorbeeld van studenten/collegezaal is beter.
Het heeft er juist alles mee te maken, ik wil geen onzinnige logica in mijn domein model. Ik wil dus niet klanten toevoegen aan mijn bestelling. Net zo goed als ik geen collegezaal wil toekennen aan een student. Dat voorbeeld is namelijk exact hetzelfde.
EfBe schreef op donderdag 08 mei 2008 @ 17:12:
Het punt is dat je kunt navigeren door je graph op de manier die je wilt. Jij kunt wel willen dat je het 'achterliggende' datamodel niet wilt weten, maar die graph management niet beschikbaar hebben is JUIST een reden waarom de achterliggende structuur je wordt opgedrongen: immers je moet nu weten welke kant van een relatie kennelijk de beheerder is van het geheel. [..]
Nee ik wil juist de mate van navigatie beperken. Ik wil geen weerspiegeling maken van het achterliggende model. Ik wil enkel schrijven puur wat ik nodig heb, en niet meerdere wegen naar Rome introduceren. Je hoeft ook helemaal niet te weten welke relatie beheerder is van het geheel omdat je niet meerdere mogelijkheden aanbied.
EfBe schreef op donderdag 08 mei 2008 @ 17:12:
Overigens heeft de afhankelijkheid van order op customer niets te maken met het achterliggende datamodel, maar met het abstracte entitymodel (waar order bv altijd afhankelijk is van customer), en dat is nu net het model waar ook jouw code op gebaseerd is. [..]
We praten langs elkaar heen...

  • EfBe
  • Registratie: Januari 2000
  • Niet online
Verwijderd schreef op vrijdag 09 mei 2008 @ 07:47:
[...]
Het heeft er juist alles mee te maken, ik wil geen onzinnige logica in mijn domein model. Ik wil dus niet klanten toevoegen aan mijn bestelling. Net zo goed als ik geen collegezaal wil toekennen aan een student. Dat voorbeeld is namelijk exact hetzelfde.
Je snapt het niet, het gaat niet over klanten toevoegen aan orders. Het gaat over het plaatsen van edges op een graph. je weet wat een graph is? Als je een directed acyclic graph maakt van je in-memory entity instance model, dan kun je niet alle kanten op navigeren, terwijl dat wel zou moeten, immers de relatie is gedefinieerd TUSSEN entities, en niet van entity X naar entity Y.
[...]
Nee ik wil juist de mate van navigatie beperken. Ik wil geen weerspiegeling maken van het achterliggende model. Ik wil enkel schrijven puur wat ik nodig heb, en niet meerdere wegen naar Rome introduceren. Je hoeft ook helemaal niet te weten welke relatie beheerder is van het geheel omdat je niet meerdere mogelijkheden aanbied.
Je leest teveel TDD boeken volgens mij. Dit is de 2e keer dat je krampachtig probeert te voorkomen dat iets achterliggends naar voren komt, maar face it: JUIST zonder graph management moet je rekening houden met wat er achterligt en plumbing code schrijven waar nodig.

Ik kan met graph management aanwezig, gewoon een graph van entities in een scherm prakken en code schrijven die de graph manipuleert zonder rekening te houden met welke kant ik de entity moet toevoegen.
Sjaaky schreef op donderdag 08 mei 2008 @ 22:48:
Dat er geen entity graph management niet in hibernate zit is mij eigenlijk ook tegengevallen. Toen we voor hibernate kozen (beetje achter de meute aangelopen...) kende ik de term niet eens. Maar uiteindelijk ben je best nog wel wat plumbing aan het schrijven om te zorgen dat je domein-model op die punten consistent blijft. Zeker om te zorgen dat classes op geen enkele manier fout gebruikt worden door collega's. Want uiteindelijk wil je wel een intuitief te gebruiken domein-model ontwikkelen.
Bingo. Dit is precies waar het om gaat: de graph management IS al ingebouwd. Dat krijg je kado, althans, bij o/r mappers die dat hebben. Dit levert dus een omgeving op die je instaat stelt meteen met de code te beginnen die er toe doet, nl. de code die je behoort te schrijven voor de klant. IEDERE REGEL CODE die je nodig hebt om wat je gebruikt ook daadwerkelijk te laten werken is plumbing en zou overbodig moeten zijn.
Daarnaast zit je je zeker in het begin nog best wel eens achter het hoofd te krabben waarom iets nu niet wordt opgeslagen in de database. De leercurve was iig steiler dan ik had verwacht. De voorbeelden zien er vaak simpel uit, maar er zijn veel subtiliteiten waar je rekening mee moet houden.
O/R mappers doen dingen anders dan wat menigeen gewend is (tabellen, SQL schrijven, recordsetjes ophalen etc. etc.) en dat kost zeker tijd om goed te leren. Hibernate is ook niet slecht ofzo, er zitten veel geavanceerde features in, maar dit aspect is toch wel een blinde vlek. Maar ach, Gavin heeft daar wel vaker een handje van ;)

[ Voor 34% gewijzigd door EfBe op 09-05-2008 08:46 ]

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


Verwijderd

Prima, laten we het daar bij :)

  • EfBe
  • Registratie: Januari 2000
  • Niet online
Verwijderd schreef op vrijdag 09 mei 2008 @ 09:13:
[...]
Prima, laten we het daar bij :)
heh :) Naja, ik bedoelde het niet als flame ofzo, gewoon dat het leek alsof de essentie van het verhaal je ontging.

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


Verwijderd

EfBe schreef op vrijdag 09 mei 2008 @ 10:38:
heh :) Naja, ik bedoelde het niet als flame ofzo, gewoon dat het leek alsof de essentie van het verhaal je ontging.
Ik vat het ook niet op als een flame en ik snap je verhaal ook helemaal maar ik zou een hele slechte advocaat van de duivel zijn als ik het direct met je eens ben ;). De reden dat ik in eerste instantie reageerde is omdat het ontbreken van bepaalde functionaliteit in welke tool dan ook niet per definitie een gebrek is. Ik wil er alleen geen eindeloze discussie van maken aangezien het niet echt bijdraagt aan probleem van TS (yes, I'm guilty).

  • EfBe
  • Registratie: Januari 2000
  • Niet online
Verwijderd schreef op vrijdag 09 mei 2008 @ 11:04:
[...]
Ik vat het ook niet op als een flame en ik snap je verhaal ook helemaal maar ik zou een hele slechte advocaat van de duivel zijn als ik het direct met je eens ben ;). De reden dat ik in eerste instantie reageerde is omdat het ontbreken van bepaalde functionaliteit in welke tool dan ook niet per definitie een gebrek is. Ik wil er alleen geen eindeloze discussie van maken aangezien het niet echt bijdraagt aan probleem van TS (yes, I'm guilty).
Heb je gelijk in :)

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com

Pagina: 1