Hibernate get parent-id aus der untergeordneten Entität
viele Leute gepostet haben sehr ähnliche Probleme, aber ich kann nicht scheinen, einen zu finden, der meine Adressen Umstand.
Habe ich eine übergeordnete Entität Dnar
- und einer untergeordneten Entität WorkLocationSuburb
. Ein Dnar
eins-zu-viele -WorkLocationSuburbs
.
Normalerweise würde ich definieren dieses Verhältnis wie folgt:
Das Kind
@Entity
@Table(name = "req_work_suburb", schema = SCHEMA)
public class WorkLocationSuburb {
@Id
@GeneratedValue(generator = "req_work_suburb_seq")
@GenericGenerator(strategy="sequence", name="req_work_suburb_seq", parameters={@Parameter(name="sequence", value=SCHEMA+".req_work_suburb_seq")})
@Column(name = "id", nullable = false)
private Long id;
@Column(name="suburb", length=255, nullable=false)
private String suburb;
//remainder omitted
}
Die Eltern
@Entity
@Table(name = "req_dnar", schema = SCHEMA)
@Inheritance(strategy = JOINED)
@DiscriminatorColumn(name = "form_type", discriminatorType = STRING, length = 64)
public abstract class Dnar {
@Id
@GeneratedValue(generator = "req_dnar_seq")
@GenericGenerator(strategy = "sequence", name = "req_dnar_seq", parameters = { @Parameter(name = "sequence", value = SCHEMA + ".req_dnar_seq") })
@Column(name = C_DNAR_ID, nullable = false)
private Long dnarId;
@Column(name = "original_id")
private Long originalId;
@OneToMany(cascade = ALL, fetch = EAGER, orphanRemoval=true)
@JoinColumn(name = "dnar_id", nullable=false)
private Set<WorkLocationSuburb> workLocationSuburbs;
//remainder omitted
}
Funktioniert das obige Beispiel, und wenn ich manuell Abfrage der req_work_suburb
Tisch, ich kann sehen, dass es dnar_id
Spalte und die Spalte ist korrekt aufgefüllt. Alles gut, so weit!
In einigen Abfrage-code, erstelle ich eine criteria-Abfrage, die in Abhängigkeit vom Wert des req_work_suburb.dnar_id
:
private static Specification<SubmittedDnarSummary> suburbIs(final String suburb) {
return new Specification<SubmittedDnarSummary>(){
@Override
public Predicate toPredicate(Root<SubmittedDnarSummary> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
Subquery<Long> subquery = query.subquery(Long.class);
Root<WorkLocationSuburb> suburbRoot = subquery.from(WorkLocationSuburb.class);
return cb.in(root.get("dnarId")).value(subquery.select(suburbRoot.<Long>get("dnarId")).where(cb.equal(suburbRoot.get("suburb"), suburb)));
}
};
}
Wenn ich führen Sie die oben, bekomme ich die folgende exception:
org.springframework.dao.InvalidDataAccessApiUsageException: Unable to resolve attribute [dnarId] against path; nested exception is java.lang.IllegalArgumentException: Unable to resolve attribute [dnarId] against path
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:301)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:106)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:403)
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:58)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:163)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.data.jpa.repository.support.LockModeRepositoryPostProcessor$LockModePopulatingMethodIntercceptor.invoke(LockModeRepositoryPostProcessor.java:91)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:90)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
at $Proxy253.findAll(Unknown Source)
at au.com.wpcorp.sys.dnar.spring.manager.impl.SearchManagerImpl.search(SearchManagerImpl.java:66)
at au.com.wpcorp.sys.dnar.spring.mvc.controller.search.DnarSearchController.results(DnarSearchController.java:97)
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.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:213)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:126)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:96)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:617)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:578)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:923)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:778)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:668)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:770)
at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1550)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:161)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:331)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
at com.sun.enterprise.v3.services.impl.ContainerMapper$AdapterCallable.call(ContainerMapper.java:317)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:195)
at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:860)
at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:757)
at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1056)
at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:229)
at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
at java.lang.Thread.run(Thread.java:662)
Caused by: java.lang.IllegalArgumentException: Unable to resolve attribute [dnarId] against path
at org.hibernate.ejb.criteria.path.AbstractPathImpl.unknownAttribute(AbstractPathImpl.java:118)
at org.hibernate.ejb.criteria.path.AbstractPathImpl.locateAttribute(AbstractPathImpl.java:223)
at org.hibernate.ejb.criteria.path.AbstractPathImpl.get(AbstractPathImpl.java:194)
at au.com.wpcorp.sys.dnar.spring.manager.impl.SearchManagerImpl$3.toPredicate(SearchManagerImpl.java:141)
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.applySpecificationToCriteria(SimpleJpaRepository.java:480)
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.getQuery(SimpleJpaRepository.java:436)
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.getQuery(SimpleJpaRepository.java:421)
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.findAll(SimpleJpaRepository.java:303)
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.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:334)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:319)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:155)
... 49 more
Scheint es zu scheitern, weil Hibernate nicht finden können, eine Eigenschaft, die man als dnarId
auf WorkLocationSuburb
. Meine Frage ist, wie kann ich diese Informationen hinzuzufügen, um WorkLocationSuburb
ohne Hibernate Klagen über ein anderes problem? Es scheint, ich brauche ein paar Codes wie:
@Entity
@Table(name = "req_work_suburb", schema = SCHEMA)
public class WorkLocationSuburb {
@Id
@GeneratedValue(generator = "req_work_suburb_seq")
@GenericGenerator(strategy="sequence", name="req_work_suburb_seq", parameters={@Parameter(name="sequence", value=SCHEMA+".req_work_suburb_seq")})
@Column(name = "id", nullable = false)
private Long id;
@Column(name="suburb", length=255, nullable=false)
private String suburb;
@Column(name="dnar_id", nullable=false) //column definition added here
private Long dnarId;
//remainder omitted
}
Weiß jemand, wie kann ich die oben genannten zusätzlichen Spalte arbeiten? Diese Spalte muss automatisch mit den Eltern dnarId
.
Dank,
Muel.
Aktualisiert mit JB Nizet Anregungen
Mein code ist jetzt so:
Das Kind
@Entity
@Table(name = "req_work_suburb", schema = SCHEMA)
public class WorkLocationSuburb {
@Id
@GeneratedValue(generator = "req_work_suburb_seq")
@GenericGenerator(strategy="sequence", name="req_work_suburb_seq", parameters={@Parameter(name="sequence", value=SCHEMA+".req_work_suburb_seq")})
@Column(name = "id", nullable = false)
private Long id;
@Column(name="suburb", length=255, nullable=false)
private String suburb;
@ManyToOne
@JoinColumn(name="dnar_id", nullable=false)
private Dnar dnar;
//remainder omitted
}
Die Eltern
@Entity
@Table(name = "req_dnar", schema = SCHEMA)
@Inheritance(strategy = JOINED)
@DiscriminatorColumn(name = "form_type", discriminatorType = STRING, length = 64)
public abstract class Dnar {
@Id
@GeneratedValue(generator = "req_dnar_seq")
@GenericGenerator(strategy = "sequence", name = "req_dnar_seq", parameters = { @Parameter(name = "sequence", value = SCHEMA + ".req_dnar_seq") })
@Column(name = C_DNAR_ID, nullable = false)
private Long dnarId;
@Column(name = "original_id")
private Long originalId;
@OneToMany(cascade = ALL, fetch = EAGER, orphanRemoval=true, mappedBy="dnar")
private Set<WorkLocationSuburb> workLocationSuburbs = new LinkedHashSet<WorkLocationSuburb>();
@PostPersist
void setChildRefs() {
for (WorkLocationSuburb suburb : workLocationSuburbs) {
suburb.setDnar(this);
}
}
//remainder omitted
}
Wenn ich Versuch zu speichern eine Dnar
hat eine WorkLocationSuburb
befestigt, sehe ich die folgende Reihenfolge der Ereignisse:
- Die
Dnar
wird in die Datenbank eingefügt @PostConstuct
aufgerufen, und dieWorkLocationSuburb
bekommt eine Referenz auf das parent -Dnar
. Die ElternDnar
wurde eine ID zugewiesen, richtig.- Die Einfügung des Kindes
WorkLocationSuburb
versucht, aber die Ergebnisse in die folgende exception: org.hibernate.Ausnahme.ConstraintViolationException: ORA-01400: cannot insert NULL into ("DNAR"."REQ_WORK_SUBURB"."DNAR_ID")`
Was bin ich eigentlich noch falsch? 🙂
Du musst angemeldet sein, um einen Kommentar abzugeben.
Die Sie gerade benötigen, um die Assoziation bidirektional:
Nur bewusst sein, dass eine bidirektionale OneToMany Assoziation, die Besitz-Seite des Vereins ist immer die N-Seite (die Seite, die nicht über die
mappedBy
- Attribut). Dies bedeutet, dass der Ruhezustand wird nur dieWorkLocationSuburb.parentDnar
Feld, um zu entscheiden, wenn der Verein existiert. Dies bedeutet also, dass jedes mal, wenn Sie einen Vorort, um eine dnar, müssen Sie außerdem den Vorort der dnar-Feld:Ähnlich, wenn Sie entfernen ein Vorort von einer dnar, sollten Sie die parentDnar der Ortschaft zu null.
Bezüglich der Abfrage, können Sie jetzt mit der
parentDnar
Feld in Ihrer Abfrage. Denken Sie daran, dass JPA-Abfragen arbeiten Sie immer auf Personen und deren persistent fields/properties. Nie auf die Tabelle und Ihre Spalten.