简体   繁体   English

如何使用 JPA 和 Hibernate 为 2 个表建立单向 @oneToMany 关系

[英]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我的项目基于 spring boot、Thymeleaf、mysql、html 和 Jquery。我试图在可维护表中建立一个单向的 @oneToMany 关系,但它只产生像这样的错误

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; ///////////////////////////////////////////////// /////////// EntPropertySub包 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请帮我解决这个问题..提前致谢

Try this: make sure how the foreign key in the table EntPopertySub called试试这个:确保表 EntPopertySub 中的外键是如何调用的

@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 关系。 OneToMany means that Master has many Sub Table references. OneToMany 意味着 Master 有很多 Sub Table 引用。

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) Hibernate 将自动为您选择所有引用的子列(实习生 Hibernate 连接到列)

If you use the entitymanager to select the master data, the sub-data is included in the List blockListPropSub attribute如果使用entitymanager选择主数据,子数据包含在List blockListPropSub属性中

The cause of the error is:错误的原因是:

Unable to find column with logical name: propertysubpk in org.hibernate.mapping.Table(property_master)无法在 org.hibernate.mapping.Table(property_master) 中找到具有逻辑名称的列:propertysubpk

The reason is that you have the referencedColumnName attribute wrong.原因是您的referencedColumnName属性错误。 It is supposed to be:它应该是:

JPA 2.1 11.1.25: The name of the column referenced by this foreign key column. JPA 2.1 11.1.25:此外键列引用的列的名称。 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.当与单向 OneToMany 外键映射一起使用时,引用的列位于源实体的表中。 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.解释一下:除非指定了referencedColumnName ,否则EntPropertySub在关系的侧(此处为@JoinColumn创建一个列,其给定名称引用父实体的PK In the latter case the FK in the "many" table references the column given in referencedColumnName .在后一种情况下,在“多”表引用的FK列中给出referencedColumnName In your case you want to reference the PK of EntPropertyMaster , so referencedColumnName is redundant.在您的情况下,您想引用EntPropertyMaster的PK,因此referencedColumnName是多余的。 Simply use:只需使用:

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

The error clearly shows mapping missing in your schema relation.该错误清楚地表明您的架构关系中缺少映射。

You need to map EntPropertyMaster in EntPropertySub .您需要在EntPropertyMaster中映射EntPropertySub

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

Provide EntPropertyMaster mapping in relation entity too.ie在关系实体中也提供EntPropertyMaster映射。ie

@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. JPA 中的关系始终是单向的,除非您将父级与子级双向关联。 Cascading REMOVE operations from the parent to the child will require a relation from the parent to the child (not just the opposite).从父级到子级的级联 REMOVE 操作将需要从父级到子级的关系(不仅仅是相反的)。

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 .在@OneToMany 关系上使用@JoinColumn 时, name属性将指向相关表列,即EntPropertySub实体,而referencedColumnName应指向存在@OneToMany 注释的实体的列,即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>();

Finnaly i got a answer..最后我得到了答案..

i made a changes in master entity "EntPropertyMaster"我对主实体“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..请注意,我们需要为列创建提供唯一名称,然后它只会在子表中创建一列......而不是子/父表的主键列名..

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM