很多人都发布了非常类似的问题,但是我似乎找不到能够解决我的情况的问题。
我有一个父实体Dnar
和一个子实体WorkLocationSuburb
。 Dnar
具有一对多的WorkLocationSuburbs
。
通常,我将这种关系定义如下:
孩子
@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
}
父母
@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
}
上面的示例有效,当我手动查询
req_work_suburb
表时,可以看到它具有dnar_id
列,并且该列已正确填充。到目前为止一切都很好!在某些查询代码中,我创建一个依赖于
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)));
}
};
}
执行上述操作时,出现以下异常:
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
由于Hibernate在
dnarId
上找不到名为WorkLocationSuburb
的属性,因此它似乎失败了。我的问题是,如何在Hibernate不抱怨其他问题的情况下将该信息添加到WorkLocationSuburb
?看来我需要一些代码,例如:@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
}
有谁知道我怎样才能使上面的附加列起作用?此列必须自动使用父级的
dnarId
填充。谢谢,
uel子
更新了JB Nizet的建议
我的代码现在如下所示:
孩子
@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
}
父母
@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
}
当我尝试保存附加了
Dnar
的WorkLocationSuburb
时,我看到以下事件顺序:Dnar
插入到数据库中调用
@PostConstuct
,并且WorkLocationSuburb
获取对父Dnar
的引用。父Dnar
已正确分配了ID。尝试插入子
WorkLocationSuburb
,但会导致以下异常:org.hibernate.exception.ConstraintViolationException:ORA-01400:无法将NULL插入(“ DNAR”。“ REQ_WORK_SUBURB”。“ DNAR_ID”)`我仍然在做错什么? :)
最佳答案
您只需要使关联双向:
public class WorkLocationSuburb {
@ManyToOne
@JoinColumn
private Dnar parentDnar;
// ...
}
public class Dnar {
@OneToMany(mappedBy = "parentDnar", ...)
private Set<WorkLocationSuburb> suburbs;
// ...
}
请注意,在双向OneToMany关联中,关联的拥有方始终是多面(不具有
mappedBy
属性的面)。这意味着休眠将仅考虑WorkLocationSuburb.parentDnar
字段来确定关联是否存在。因此,这意味着每次将郊区添加到dnar时,还必须设置郊区的dnar字段:public void addSuburb(WorkLocationSuburb suburb) {
this.suburbs.add(suburb);
suburb.setParentDnar(this);
}
同样,如果从dnar中删除郊区,则应将郊区的parentDnar设置为null。
关于查询,您现在可以在查询中使用
parentDnar
字段。请记住,JPA查询始终对实体及其持久字段/属性起作用。切勿在桌子及其柱子上。