加入表@OneToMany / @ManyToOne

Posted

技术标签:

【中文标题】加入表@OneToMany / @ManyToOne【英文标题】:joining tables @OneToMany / @ManyToOne 【发布时间】:2016-10-07 14:28:20 【问题描述】:

对于我尝试加入表格的小任务。我对 mysql 和 Java 有一些经验,但对 Spring、Hibernate 和 HSQL 不熟悉。

我以前使用过联接,但我不是专业人士,而且该框架对我来说也是新的......不是一个巨大的变化,但我不确定问题出在哪里......

我已经创建了一些连接表和相关类,但现在我希望每个客户记录都有一个员工 ID 的外键。 iǘe 尝试了一些不同的设置,但无济于事,这就是我现在的位置。

我收到以下错误:

java.lang.IllegalStateException: Failed to load ApplicationContext

at org.springframework.test.context.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:94)
at org.springframework.test.context.DefaultTestContext.getApplicationContext(DefaultTestContext.java:72)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:117)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:212)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:200)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:259)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:261)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:219)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:83)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:68)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:163)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:117)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:262)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:84)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in nl.mad.w2l2.ApplicationConfig: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1574)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:956)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:747)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:125)
at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:60)
at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.delegateLoading(AbstractDelegatingSmartContextLoader.java:109)
at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.loadContext(AbstractDelegatingSmartContextLoader.java:261)
at org.springframework.test.context.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:68)
at org.springframework.test.context.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:86)
... 29 more

Caused by: javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.persistenceException(EntityManagerFactoryBuilderImpl.java:1239)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.access$600(EntityManagerFactoryBuilderImpl.java:120)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:855)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:845)
at org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl.withTccl(ClassLoaderServiceImpl.java:398)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:844)
at org.hibernate.jpa.HibernatePersistenceProvider.createContainerEntityManagerFactory(HibernatePersistenceProvider.java:152)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:343)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:318)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1633)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1570)
... 44 more

Caused by: org.hibernate.AnnotationException: Illegal attempt to map a non collection as a @OneToMany, @ManyToMany or @CollectionOfElements: nl.mad.w2l2.model.Employee.bsn
at org.hibernate.cfg.annotations.CollectionBinder.getCollectionBinder(CollectionBinder.java:330)
at org.hibernate.cfg.AnnotationBinder.processElementAnnotations(AnnotationBinder.java:1922)
at org.hibernate.cfg.AnnotationBinder.processIdPropertiesIfNotAlready(AnnotationBinder.java:963)
at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:796)
at org.hibernate.cfg.Configuration$MetadataSourceQueue.processAnnotatedClassesQueue(Configuration.java:3845)
at org.hibernate.cfg.Configuration$MetadataSourceQueue.processMetadata(Configuration.java:3799)
at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1412)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1846)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:852)
... 52 more

最后一个错误让我相信我在连接上做错了什么。我已经搜索和搜索,尝试了一个或 2 个教程,但我认为我忽略了一些东西......我已经重写并删除了我的大部分代码以查明问题但没有成功:( 它可能是一个真实的愚蠢的错误或疏忽,非常抱歉并提前感谢!:)

抽象用户类:

@Entity
@Table(name = "user")
@Inheritance(strategy = JOINED)
@DiscriminatorColumn(name = "type")
public abstract class User extends BaseEntity 

private String email;

子类员工

@Entity
//@Table(name = "employee")
@DiscriminatorValue("employee")
@PrimaryKeyJoinColumn(name = "user_id")
public class Employee extends User 

@OneToMany
@JoinColumn(name="accountant_id")

private String bsn;

子类客户

@Entity
//@Table(name = "customer")
@DiscriminatorValue("customer")
@PrimaryKeyJoinColumn(name = "user_id")
public class Customer extends User 

@ManyToOne
@JoinColumn(name="id")

private BigDecimal balance;

还有我的数据库创建方案

-- user --
CREATE TABLE public.user (
  id BIGINT IDENTITY,
  type VARCHAR (50) NOT NULL,
  email VARCHAR (50) NOT NULL,
);
CREATE UNIQUE INDEX ix_user_email ON public.user(email);

-- customer --
CREATE TABLE public.customer (
  id BIGINT IDENTITY,
  user_id BIGINT NOT NULL,
  accountant_id BIGINT,
  balance NUMERIC(19,2) NOT NULL,
);
ALTER TABLE public.customer
  ADD CONSTRAINT fk_customer_user_id FOREIGN KEY (user_id) REFERENCES public.user(id);
ALTER TABLE public.customer
  ADD CONSTRAINT fk_customer_employee_id FOREIGN KEY (accountant_id) REFERENCES public.user(id);


-- employee --
CREATE TABLE public.employee (
  id BIGINT IDENTITY,
  user_id BIGINT NOT NULL,
  bsn VARCHAR(9) NOT NULL
);
ALTER TABLE public.employee
  ADD CONSTRAINT fk_employee_user_id FOREIGN KEY (user_id) REFERENCES public.user(id);
CREATE UNIQUE INDEX ix_employee_bsn ON public.employee(bsn);

提前致谢!!!

【问题讨论】:

【参考方案1】:

错误提示:

非法尝试将非集合映射为@OneToMany、@ManyToMany 或@CollectionOfElements:nl.mad.w2l2.model.Employee.bsn

对应的代码是

@OneToMany
@JoinColumn(name="accountant_id")
private String bsn;

这没有任何意义。 OneToMany 用于告诉 Hibernate 一个员工(例如)有许多任务,并且这些任务中的每一个都只属于这个员工。它是两种实体类型之间的关联,因此它必须注释实体集合,例如

@OneToMany
private Set<Task> tasks;

【讨论】:

我同意你的看法,但为什么会话工厂创建中会出现失败,它不应该出现在尝试将实体移动到持久性上下文时吗? 在创建会话工厂时会发生这种情况,因为此时 Hibernate 会读取所有映射以了解它必须处理哪些实体以及它们如何相互链接。 public class Customer extends User @ManyToOne @JoinColumn(name="id") private Employee employee;public class Employee extends User @OneToMany @JoinColumn(name="id") private List&lt;User&gt; accounts; 似乎可以解决问题...随附的单元测试仍然失败,但至少我在正确的轨道上:) thx!

以上是关于加入表@OneToMany / @ManyToOne的主要内容,如果未能解决你的问题,请参考以下文章

Mysql OneToMany 只加入最近的记录

Hibernate/JPA 多对一与单对多

非主键之间的休眠关系OneToMany

如何使用 Hibernate Criteria 连接两个具有 OneToMany 关系的表

不加入子表的 JPA (@OneToMany) 查询

加入获取嵌套在 @OneToMany 中的 @ManyToOne