Vignesh R
Vignesh R

Reputation: 211

How to make unidirectional @oneToMany relationship for 2 tables using JPA and Hibernate

My project based on spring boot,Thymeleaf,mysql,html and Jquery.I tried to make a @oneToMany Relation with unidirectional in maintable,but it produces only error like

2017-10-23 16:17:49.908 ERROR 18724 --- [           main] o.s.boot.SpringApplication               : Application startup failed
 
 org.springframework.beans.factory.BeanCreationException: Error
 creating bean with name 'entityManagerFactory' defined in class path
 resource
 [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.class]:
 Invocation of init method failed; nested exception is
 org.hibernate.AnnotationException: **Unable to map collection
 com.vfraternity.process.entity.EntPropertyMaster.blockListPropSub**   at
 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1702)
 ~[spring-beans-5.0.0.RC4.jar:5.0.0.RC4]   at
 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:583)
 ~[spring-beans-5.0.0.RC4.jar:5.0.0.RC4]   at
 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:502)
 ~[spring-beans-5.0.0.RC4.jar:5.0.0.RC4]   at
 org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:312)
 ~[spring-beans-5.0.0.RC4.jar:5.0.0.RC4]   at
 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
 ~[spring-beans-5.0.0.RC4.jar:5.0.0.RC4]   at
 org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:310)
 ~[spring-beans-5.0.0.RC4.jar:5.0.0.RC4]   at
 org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200)
 ~[spring-beans-5.0.0.RC4.jar:5.0.0.RC4]   at
 org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1083)
 ~[spring-context-5.0.0.RC4.jar:5.0.0.RC4]     at
 org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:858)
 ~[spring-context-5.0.0.RC4.jar:5.0.0.RC4]     at
 org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549)
 ~[spring-context-5.0.0.RC4.jar:5.0.0.RC4]     at
 org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:122)
 ~[spring-boot-2.0.0.M4.jar:2.0.0.M4]  at
 org.springframework.boot.SpringApplication.refresh(SpringApplication.java:750)
 [spring-boot-2.0.0.M4.jar:2.0.0.M4]   at
 org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:386)
 [spring-boot-2.0.0.M4.jar:2.0.0.M4]   at
 org.springframework.boot.SpringApplication.run(SpringApplication.java:327)
 [spring-boot-2.0.0.M4.jar:2.0.0.M4]   at
 org.springframework.boot.SpringApplication.run(SpringApplication.java:1245)
 [spring-boot-2.0.0.M4.jar:2.0.0.M4]   at
 org.springframework.boot.SpringApplication.run(SpringApplication.java:1233)
 [spring-boot-2.0.0.M4.jar:2.0.0.M4]   at
 com.vfraternity.VfSpringBootMain.main(VfSpringBootMain.java:12)
 [classes/:na] Caused by: org.hibernate.AnnotationException: Unable to
 map collection
 com.vfraternity.process.entity.EntPropertyMaster.blockListPropSub     at
 org.hibernate.cfg.annotations.CollectionBinder.bindCollectionSecondPass(CollectionBinder.java:1604)
 ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]   at
 org.hibernate.cfg.annotations.CollectionBinder.bindOneToManySecondPass(CollectionBinder.java:871)
 ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]   at
 org.hibernate.cfg.annotations.CollectionBinder.bindStarToManySecondPass(CollectionBinder.java:786)
 ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]   at
 org.hibernate.cfg.annotations.CollectionBinder$1.secondPass(CollectionBinder.java:725)
 ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]   at
 org.hibernate.cfg.CollectionSecondPass.doSecondPass(CollectionSecondPass.java:54)
 ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]   at
 org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1621)
 ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]   at
 org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1589)
 ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]   at
 org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:278)
 ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]   at
 org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:858)
 ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]   at
 org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:885)
 ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]   at
 org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:57)
 ~[spring-orm-5.0.0.RC4.jar:5.0.0.RC4]     at
 org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:358)
 ~[spring-orm-5.0.0.RC4.jar:5.0.0.RC4]     at
 org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:384)
 ~[spring-orm-5.0.0.RC4.jar:5.0.0.RC4]     at
 org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:373)
 ~[spring-orm-5.0.0.RC4.jar:5.0.0.RC4]     at
 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods AbstractAutowireCapableBeanFactory.java:1761)
 ~[spring-beans-5.0.0.RC4.jar:5.0.0.RC4]   at
 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1698)
 ~[spring-beans-5.0.0.RC4.jar:5.0.0.RC4]   ... 16 common frames omitted
 Caused by: org.hibernate.cfg.RecoverableException: Unable to find
 column with logical name: propertysubpk in
 org.hibernate.mapping.Table(property_master) and its related
 supertables and secondary tables  at
 org.hibernate.cfg.Ejb3JoinColumn.checkReferencedColumnsType(Ejb3JoinColumn.java:831)
 ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]   at
 org.hibernate.cfg.BinderHelper.createSyntheticPropertyReference(BinderHelper.java:243)
 ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]   at
 org.hibernate.cfg.annotations.CollectionBinder.bindCollectionSecondPass(CollectionBinder.java:1594)
 ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]   ... 31 common frames
 omitted Caused by: org.hibernate.MappingException: Unable to find
 column with logical name: propertysubpk in
 org.hibernate.mapping.Table(property_master) and its related
 supertables and secondary tables  at
 org.hibernate.cfg.Ejb3JoinColumn.checkReferencedColumnsType(Ejb3JoinColumn.java:826)
 ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]   ... 33 common frames
 omitted

I tried to achive unidirectional using

@OneToMany(cascade=CascadeType.ALL)
@JoinColumn(name="propertysubfkid", referencedColumnName="propertysubpk")
private List<EntPropertySub> blockListPropSub = newArrayList<EntPropertySub>();

But it produces only error... Here is my complete codes..

**EntPropertyMaster** 

package com.vfraternity.process.entity;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Version;
import javax.validation.constraints.NotNull;


@Entity
@Table(name="Property_Master")
public class EntPropertyMaster implements Serializable{

/**
 * 
 */
private static final long serialVersionUID = 6162594257264775391L;
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="propertyid")
private int property_id;
@NotNull
private String property_name;
@NotNull
private String address1;
@NotNull
@Column(columnDefinition="varchar(15) default'None'")
private String address2;
@NotNull
private String city;
@NotNull
private String state;
@NotNull
private String country;
@NotNull
private int zipcode;

@OneToMany(cascade=CascadeType.ALL)
@JoinColumn(name="propertysubfkid", referencedColumnName="propertysubpk")
private List<EntPropertySub> blockListPropSub = new ArrayList<EntPropertySub>();

@Version
private int version;
private Boolean is_active;
private String created_by;
private Date created_ts;
private String modified_by;
private Date modified_ts;
private String approved_by;
private Date approved_ts;





public EntPropertyMaster() {
    
}
//Getter Setter
public int getProperty_id() {
    return property_id;
}
public void setProperty_id(int property_id) {
    this.property_id = property_id;
}
public String getProperty_name() {
    return property_name;
}
public void setProperty_name(String property_name) {
    this.property_name = property_name;
}
public String getAddress1() {
    return address1;
}
public void setAddress1(String address1) {
    this.address1 = address1;
}
public String getAddress2() {
    return address2;
}
public void setAddress2(String address2) {
    this.address2 = address2;
}
public String getCity() {
    return city;
}
public void setCity(String city) {
    this.city = city;
}
public String getState() {
    return state;
}
public void setState(String state) {
    this.state = state;
}
public String getCountry() {
    return country;
}
public void setCountry(String country) {
    this.country = country;
}
public int getVersion() {
    return version;
}
public void setVersion(int version) {
    this.version = version;
}
public Boolean getIs_active() {
    return is_active;
}
public void setIs_active(Boolean is_active) {
    this.is_active = is_active;
}
public String getCreated_by() {
    return created_by;
}
public void setCreated_by(String created_by) {
    this.created_by = created_by;
}
public Date getCreated_ts() {
    return created_ts;
}
public void setCreated_ts(Date created_ts) {
    this.created_ts = created_ts;
}
public String getModified_by() {
    return modified_by;
}
public void setModified_by(String modified_by) {
    this.modified_by = modified_by;
}
public Date getModified_ts() {
    return modified_ts;
}
public void setModified_ts(Date modified_ts) {
    this.modified_ts = modified_ts;
}
public String getApproved_by() {
    return approved_by;
}
public void setApproved_by(String approved_by) {
    this.approved_by = approved_by;
}
public Date getApproved_ts() {
    return approved_ts;
}
public void setApproved_ts(Date approved_ts) {
    this.approved_ts = approved_ts;
}
public int getZipcode() {
    return zipcode;
}
public void setZipcode(int zipcode) {
    this.zipcode = zipcode;
}
public List<EntPropertySub> getBlockListPropSub() {
    return blockListPropSub;
}
public void setBlockListPropSub(List<EntPropertySub> blockListPropSub) {
    this.blockListPropSub = blockListPropSub;
}
}

///////////////////////////////////////////////////////////// EntPropertySub package com.vfraternity.process.entity;

import java.io.Serializable;
import java.util.Date;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.Version;
import javax.validation.constraints.NotNull;

@Entity
@Table(name="propertysub")
public class EntPropertySub implements Serializable
{

/**
 * 
 */
private static final long serialVersionUID = 810618405796553525L;
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="propertysubpk")
private int propertySub_pk;

@NotNull
private String blockname;
@NotNull
private int floors;
@NotNull
private String flatstart;
private String flatend;

@Version
private int version;
private Boolean is_active;
private String created_by;
private Date created_ts;
private String modified_by;
private Date modified_ts;
private String approved_by;
private Date approved_ts;

public EntPropertySub() {
    
}


//Getter Setter
public int getPropertySub_pk() {
    return propertySub_pk;
}
public void setPropertySub_pk(int propertySub_pk) {
    this.propertySub_pk = propertySub_pk;
}
public String getBlockname() {
    return blockname;
}
public void setBlockname(String blockname) {
    this.blockname = blockname;
}
public int getFloors() {
    return floors;
}
public void setFloors(int floors) {
    this.floors = floors;
}
public String getFlatstart() {
    return flatstart;
}
public void setFlatstart(String flatstart) {
    this.flatstart = flatstart;
}
public String getFlatend() {
    return flatend;
}
public void setFlatend(String flatend) {
    this.flatend = flatend;
}
public int getVersion() {
    return version;
}
public void setVersion(int version) {
    this.version = version;
}
public Boolean getIs_active() {
    return is_active;
}
public void setIs_active(Boolean is_active) {
    this.is_active = is_active;
}
public String getCreated_by() {
    return created_by;
}
public void setCreated_by(String created_by) {
    this.created_by = created_by;
}
public Date getCreated_ts() {
    return created_ts;
}
public void setCreated_ts(Date created_ts) {
    this.created_ts = created_ts;
}
public String getModified_by() {
    return modified_by;
}
public void setModified_by(String modified_by) {
    this.modified_by = modified_by;
}
public Date getModified_ts() {
    return modified_ts;
}
public void setModified_ts(Date modified_ts) {
    this.modified_ts = modified_ts;
}
public String getApproved_by() {
    return approved_by;
}
public void setApproved_by(String approved_by) {
    this.approved_by = approved_by;
}
public Date getApproved_ts() {
    return approved_ts;
}
public void setApproved_ts(Date approved_ts) {
    this.approved_ts = approved_ts;
}
}

Please help me to solve this..Thanks in advance

Upvotes: 1

Views: 14165

Answers (5)

Muhammed Misir
Muhammed Misir

Reputation: 481

Try this: make sure how the foreign key in the table EntPopertySub called

@OneToMany(cascade=CascadeType.ALL)
@JoinColumn(name="propertyid")
private List<EntPropertySub> blockListPropSub = new ArrayList<EntPropertySub>();

It's not possible to create a physical column on the master table because you have a OneToMany relation. OneToMany means that Master has many Sub Table references.

Let's explain the Problem:

If you would have a column in the master table you need to would add a list of references in one cell.

For Example

------------------ | sub-fk | |1, 2, 3, 4| <-- and this is against the database normalization

But this is not necessary:

Hibernate will automatically select all the referenced sub-columns for you (intern hibernate joins to the columns)

If you use the entitymanager to select the master data, the sub-data is included in the List blockListPropSub attribute

Upvotes: 1

Vignesh R
Vignesh R

Reputation: 211

Finnaly i got a answer..

i made a changes in master entity "EntPropertyMaster"

"@OneToMany(cascade=CascadeType.ALL)"
"@JoinColumn(name="propertyidfk")"  
private List<EntPropertySub> blockListPropSub = new ArrayList<EntPropertySub>();

It will create column in child table,but i wrote this code in parent Entity...

Please Note we need to give unique name for column creation,Then only it creates a column in child table.... not a primarykey column name of child /parent table..

Upvotes: 0

Harshal Patil
Harshal Patil

Reputation: 6759

The error clearly shows mapping missing in your schema relation.

You need to map EntPropertyMaster in EntPropertySub.

@OneToMany(cascade=CascadeType.ALL, mappedBy="entPropertyMaster")
private List<EntPropertySub> blockListPropSub = newArrayList<EntPropertySub>();

Provide EntPropertyMaster mapping in relation entity too.i.e.

@ManyToOne
@JoinColumn(name="entPropertyMasterId",referencedColumnName="id")
private EntPropertyMaster entPropertyMaster;

Relationships in JPA are always unidirectional, unless you associate the parent with the child in both directions. Cascading REMOVE operations from the parent to the child will require a relation from the parent to the child (not just the opposite).

Upvotes: 0

Nikos Paraskevopoulos
Nikos Paraskevopoulos

Reputation: 40318

The cause of the error is:

Unable to find column with logical name: propertysubpk in org.hibernate.mapping.Table(property_master)

The reason is that you have the referencedColumnName attribute wrong. It is supposed to be:

JPA 2.1 11.1.25: The name of the column referenced by this foreign key column. When used with entity relationship mappings other than the cases described below, the referenced column is in the table of the target entity. When used with a unidirectional OneToMany foreign key mapping, the referenced column is in the table of the source entity. When used inside a Join- Table annotation, the referenced key column is in the entity table of the owning entity, or inverse entity if the join is part of the inverse join definition. When used in a collection table mapping, the referenced column is in the table of the entity containing the collection.

To explain: a @JoinColumn creates a column in the many side of the relation (the EntPropertySub here) with the given name that references the PK of the parent entity, unless referencedColumnName is specified. In the latter case the FK in the "many" table references the column given in referencedColumnName. In your case you want to reference the PK of EntPropertyMaster, so referencedColumnName is redundant. Simply use:

@OneToMany(cascade=CascadeType.ALL)
@JoinColumn(name="propertysubfkid")
private List<EntPropertySub> blockListPropSub = newArrayList<EntPropertySub>();

Upvotes: 3

Maciej Kowalski
Maciej Kowalski

Reputation: 26572

When you use the @JoinColumn on a @OneToMany relationship, the name attribute will point to the relating tables column, that is EntPropertySub entity and the referencedColumnName should be pointing to the column of the entity in which the @OneToMany annotation is present, that is EntPropertyMaster.

So basically you have it other way round and it should be in my opinion:

@OneToMany(cascade=CascadeType.ALL)
@JoinColumn(name="propertysubpk", referencedColumnName="propertysubfkid")
private List<EntPropertySub> blockListPropSub = newArrayList<EntPropertySub>();

Upvotes: 0

Related Questions