Kenny Kenny - 2 months ago 11
MySQL Question

joining tables @OneToMany / @ManyToOne

For a small assignment im trying to join tables. I have some experience with MySQL & Java but am new to Spring, Hibernate & HSQL.

I've worked with joins before but im no pro and the framework is new to me as well... not a huge change but im not sure where the problem lies anymore...

I already created some joined tables and correlating classes but now i want every Customer record to have a foreign key to the employee id. iǘe tried some different setups but to no avail and here is where i am now.

im recieving the following errors:

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


the last error makes me believe im doing something wrong with the joins. I've searched and searched, tried a tutorial or 2 but i think im overlooking something... I've re-written and removed most of my code in order to pin-point the issue but no succes :( Itś probably a real noobish mistake or oversight, so sorry & thanks in advance! :)

abstract User class:

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

private String email;


subclass Employee

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

@OneToMany
@JoinColumn(name="accountant_id")

private String bsn;


subclass Customer

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

@ManyToOne
@JoinColumn(name="id")

private BigDecimal balance;


And my Database creation scheme

-- 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);


MANY MANY THANKS IN ADVANCE!!!

Answer

The error says:

Illegal attempt to map a non collection as a @OneToMany, @ManyToMany or @CollectionOfElements: nl.mad.w2l2.model.Employee.bsn

The corresponding code is

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

That makes no sense. OneToMany is used to tell Hibernate that one Employee (for example) has many tasks, and that each of these tasks belong to this employee only. It's an association between two entity types, and it must thus annotate a collection of entities, like for example

@OneToMany
private Set<Task> tasks;