Jak poprawnie kaskadowo zapisać relację jeden do jednego, dwukierunkową na kluczu głównym w Hibernate 3.6
Mam relację jeden do jednego, dwukierunkową z kluczami współdzielonymi. Kiedy próbuję uratować właściciela związku, dostaję wyjątek "null id generated" przeciwko posiadanej stronie Związku. Używam Hibernate-entitymanager i używam springa do zarządzania transakcjami.
Posiadanie Podmiotu
@Entity
@Table(name = "lead")
public class Lead
{
private Long leadId;
private LeadAffiliate leadAffiliate;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Long getLeadId()
{
return leadId;
}
@OneToOne(cascade = CascadeType.ALL)
@PrimaryKeyJoinColumn
public LeadAffiliate getLeadAffiliate()
{
return leadAffiliate;
}
}
Owned Entity
@Entity
@Table(name = "lead_affiliate")
public class LeadAffiliate
{
private Long leadId;
private Lead lead;
@Id
public Long getLeadId()
{
return leadId;
}
@MapsIdmappedBy = "leadAffiliate")
@OneToOne(cascade = CascadeType.All)
@PrimaryKeyJoinColumn
@JoinColumn(name = "lead_id")
public Lead getLead()
{
return lead;
}
}
I poniższy kod jest używany do zapisania encji:
LeadAffiliate aff = new LeadAffiliate();
aff.setLead(lead);
lead.setLeadAffiliate(aff);
em.persist(lead);
To wszystko działa doskonale w hibernate 3.5.0-Wersja ostateczna. Podczas próby aktualizacji do wersji 3.5.6-Final lub 3.6.0.Ostatecznie zaczynam otrzymywać "null id wygenerowany dla LeadAffiliate" błąd:
javax.persistence.PersistenceException: org.hibernate.id.IdentifierGenerationException: null id generated for:class com.sellingsource.bizdev.entities.LeadAffiliate
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1214)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1147)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1153)
at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:678)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:365)
at $Proxy152.persist(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:240)
at $Proxy120.persist(Unknown Source)
at com.sellingsource.common.dao.JpaGenericDao.create(JpaGenericDao.java:38)
... 64 more
Caused by: org.hibernate.id.IdentifierGenerationException: null id generated for:class com.sellingsource.bizdev.entities.LeadAffiliate
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:123)
at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:69)
at org.hibernate.event.def.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:179)
at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:135)
at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:799)
at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:791)
at org.hibernate.engine.EJB3CascadingAction$1.cascade(EJB3CascadingAction.java:48)
at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:392)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:335)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:204)
at org.hibernate.engine.Cascade.cascade(Cascade.java:161)
at org.hibernate.event.def.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:450)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:282)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:203)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:129)
at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:69)
at org.hibernate.event.def.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:179)
at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:135)
at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:61)
at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:808)
at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:782)
at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:786)
at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:672)
... 77 more
Na bok, nie jestem pewien, że adnotacje na ołowiu partnerski były całkiem słuszne na początek. Zadziałały, ale wydawały się trochę kludgey. Więc od tego czasu zmieniłem je na:
@Entity
@Table(name = "lead_affiliate")
public class LeadAffiliate
{
private Long leadId;
private Lead lead;
@Id
@GenericGenerator(name = "foreign", strategy = "foreign", parameters = {
@org.hibernate.annotations.Parameter(name = "property", value="lead")
})
@GeneratedValue(generator = "foreign")
public Long getLeadId()
{
return leadId;
}
@OneToOne(mappedBy = "leadAffiliate")
@PrimaryKeyJoinColumn
public Lead getLead()
{
return lead;
}
}
Jednak z tymi zmianami otrzymuję ten sam wynik. (Działa w 3.5.0, ale nie w 3.5.6 lub 3.6.0)
Czy jest nowy sposób, w jaki muszę być robisz to, czy to robak? Obawiam się, że mój kod działa z powodu błędu :/.
2 answers
Specyfikacja mówi, że podmiot Pochodny powinien być stroną posiadającą relacji:
2.4.1 klucze podstawowe odpowiadające identyfikatorom pochodnym
Tożsamość podmiot może pochodzić z tożsamość innego podmiotu (the podmiot "macierzysty"), gdy były encja (podmiot" zależny") to właściciel many-To-one lub one-to-one stosunek do jednostki dominującej i klucz obcy mapuje relację od zależnego do rodzic.
W Twoim przypadku LeadAffiliate
jest pochodną, więc powinien to być właściciel, gdy {[3] } powinien być oznaczony jako strona nie posiadająca przez mappedBy
. W wersji 3.5.0 i 3.5.6 działa:
public class Lead {
@Id @GeneratedValue
private Long leadId;
@OneToOne(cascade = CascadeType.ALL, mappedBy = "lead")
private LeadAffiliate leadAffiliate;
...
}
.
public class LeadAffiliate {
@Id
private Long leadId;
@OneToOne @MapsId
private Lead lead;
...
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-26 21:23:42
Moja odpowiedź nie wyjaśni, dlaczego rzeczy działają z Hibernate 3.5.0-Final, ale nie z 3.5.6-Final lub 3.6.0.Końcowe (i należy to zgłosić, nazywam to regresją).
W każdym razie, pochodne identyfikatory są znacznie lepiej obsługiwane w JPA 2.0, w standardowy sposób, a w Twoim przypadku, myślę, że możesz po prostu opisać swoją relację OneToOne
za pomocą adnotacji Id
.
Update: jak podkreślono w axtavt, przy użyciu pochodnego identyfikatora, podmiot "zależny" musi być właściciel związku. Tak więc pełne odwzorowanie dla jednostki zależnej brzmiałoby:
@Entity
@Table(name = "lead_affiliate")
public class LeadAffiliate {
private Lead lead;
@Id
@OneToOne
@JoinColumn(name="FK")
public Lead getLead() {
return lead;
}
}
I podmiot "macierzysty":
@Entity
@Table(name = "lead")
public class Lead {
private Long leadId;
private LeadAffiliate leadAffiliate;
@Id @GeneratedValue(strategy = GenerationType.AUTO)
public Long getLeadId() {
return leadId;
}
@OneToOne(cascade = CascadeType.ALL, mappedBy="lead")
public LeadAffiliate getLeadAffiliate() {
return leadAffiliate;
}
}
Jest to poprawne odwzorowanie JPA 2.0, i współpracuje z EclipseLink. Jednak Hibernate tego nie lubi i nie tworzy instancji EntityManagerFactory
(cholera!).
Jako obejście będziesz musiał użyć rozwiązania zasugerowanego przez axtavt , tj. zadeklarować atrybut klucza podstawowego , a także atrybut relacji i użyć MapsId
na atrybut relacji.
Ale powyższe powinno zadziałać, jest IMO błąd w Hibernate(zgłoszony jako HHH-5695).
Referencje
- Specyfikacja JPA 2.0
- W 2007 roku, w wyniku połączenia dwóch firm, firma została przekształcona w Spółkę Akcyjną.]}
- JPA Wikibook
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:01:40