Spring:双向 OneToMany/ManyToOne 关系中的 AnnotationException
Spring: AnnotationException in bidirectional OneToMany/ManyToOne relation
我有一个 Spring Boot - Javafx 项目有数百个 类 并且我实际上经常使用双向 OneToMany/ManyToOne 关系。这就是为什么我真的很困惑,我不明白我的问题的根本原因,因为这本质上应该是我的另一个 类 的 copy/paste 练习。我尝试在团队和员工之间添加 OneToMany/ManyToOne 关系,这样每个团队可以分配多个员工,每个员工只能是一个团队的成员,如下所示:
package com.agiletunes.shared.domain.security;
import java.io.Serializable;
import java.util.List;
import javax.persistence.Access;
import javax.persistence.AccessType;
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 com.agiletunes.shared.domain.organization.Team;
import javafx.collections.FXCollections;
@Entity
@Access(AccessType.PROPERTY) // JPA reading and writing attributes through their getter and setter methods
public class Employee implements Serializable {
private static final long serialVersionUID = 5647322135074737334L;
public static final double DEFAULT_CAPACITY = 6.5; // Default effective working hours per day per employee
private Long id;
protected String name;
protected String firstname;
protected String account; // references "name" field in Account class
protected String phone;
protected String mobile;
protected String emailAddress;
protected List<Role> roles;
protected boolean isIntern;
protected double capacityPerDay;
protected Team team;
// JPA default constructor
public Employee() {
roles = FXCollections.observableArrayList();
isIntern = true;
}
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
public Long getId() {
return id;
}
@SuppressWarnings("unused") // used by JPA
private void setId(Long id) {
this.id = id;
}
// getter and setter of other fields deleted for brevity
@ManyToOne
@JoinColumn(name = "fk_team")
public Team getTeam() {
return team;
}
public void setTeam(Team newTeam) {
if(team != newTeam) {
team = newTeam;
team.addMember(this);
}
}
@Override
public String toString() {
return getName() + ", " + getFirstname();
}
@Override // taken from Vlad Mihalcea
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Employee )) return false;
return id != null && id.equals(((Employee) o).getId());
}
@Override
public int hashCode() {
return 31;
}
}
和
package com.agiletunes.shared.domain.organization;
import java.io.Serializable;
import java.util.List;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Version;
import com.agiletunes.shared.domain.requirements.UserRequirement;
import com.agiletunes.shared.domain.security.Employee;
import javafx.collections.FXCollections;
@Entity
@Access(AccessType.PROPERTY)
public class Team implements Serializable {
private static final long serialVersionUID = 5479263131702523523L;
private Long id;
private Integer version;
protected String identifier;
protected double capacityPerDay;
protected List<UserRequirement> userRequirements; // the teams backlog
protected List<Employee> members;
// JPA default constructor
public Team() {
userRequirements = FXCollections.observableArrayList();
members = FXCollections.observableArrayList();
}
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
protected Long getId() {
return id;
}
protected void setId(Long id) {
this.id = id;
}
// getter and setter of other fields deleted for brevity
@OneToMany(mappedBy="team")
public List<Employee> getMembers() {
return members;
}
protected void setMembers(List<Employee> newMembers) {
this.members = FXCollections.observableList(newMembers);
}
public void addMember(Employee member) {
if( ! members.contains(member)) {
if(members.add(member)) {
setCapacityPerDay(getCapacityPerDay() + Employee.DEFAULT_CAPACITY);
}
member.setTeam(this);
}
}
public void delMember(Employee member) {
if(members.contains(member)) {
if(members.remove(member)) {
setCapacityPerDay(getCapacityPerDay() - Employee.DEFAULT_CAPACITY);
}
member.setTeam(null);
}
}
@Override
public String toString() {
return identifier;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Team )) return false;
return id != null && id.equals(((Team) o).getId());
}
@Override
public int hashCode() {
return 31;
}
}
此代码导致
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'organizationEntityManagerFactory' defined in class path resource [com/agiletunes/security/OrganizationConfig.class]: Invocation of init method failed; nested exception is org.hibernate.AnnotationException: @OneToOne or @ManyToOne on com.agiletunes.shared.domain.security.Employee.team references an unknown entity: com.agiletunes.shared.domain.organization.Team
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1778)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:593)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean[=14=](AbstractBeanFactory.java:320)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1105)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:742)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:389)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:311)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1213)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1202)
at com.agiletunes.security.AuthServerApp.init(AuthServerApp.java:73)
at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:841)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication9(LauncherImpl.java:182)
at java.lang.Thread.run(Thread.java:748)
Caused by: org.hibernate.AnnotationException: @OneToOne or @ManyToOne on com.agiletunes.shared.domain.security.Employee.team references an unknown entity: com.agiletunes.shared.domain.organization.Team
at org.hibernate.cfg.ToOneFkSecondPass.doSecondPass(ToOneFkSecondPass.java:97)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processEndOfQueue(InFlightMetadataCollectorImpl.java:1827)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processFkSecondPassesInOrder(InFlightMetadataCollectorImpl.java:1771)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1658)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:287)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:904)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:935)
at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:57)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:365)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:390)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:377)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:341)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1837)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1774)
... 18 common frames omitted
这是什么,我没看到?感谢您的帮助和时间
我会检查您的 LocalContainerEntityManagerFactoryBean
是否真的正确配置为扫描包 com.agiletunes.shared.domain.security
和 com.agiletunes.shared.domain.organization
以查找实体 类。
应该是:
localContainerEntityManagerFactoryBean.setPackagesToScan(
"com.agiletunes.shared.domain.security",
"com.agiletunes.shared.domain.organization");
或:
localContainerEntityManagerFactoryBean.setPackagesToScan(
"com.agiletunes.shared.domain");
我有一个 Spring Boot - Javafx 项目有数百个 类 并且我实际上经常使用双向 OneToMany/ManyToOne 关系。这就是为什么我真的很困惑,我不明白我的问题的根本原因,因为这本质上应该是我的另一个 类 的 copy/paste 练习。我尝试在团队和员工之间添加 OneToMany/ManyToOne 关系,这样每个团队可以分配多个员工,每个员工只能是一个团队的成员,如下所示:
package com.agiletunes.shared.domain.security;
import java.io.Serializable;
import java.util.List;
import javax.persistence.Access;
import javax.persistence.AccessType;
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 com.agiletunes.shared.domain.organization.Team;
import javafx.collections.FXCollections;
@Entity
@Access(AccessType.PROPERTY) // JPA reading and writing attributes through their getter and setter methods
public class Employee implements Serializable {
private static final long serialVersionUID = 5647322135074737334L;
public static final double DEFAULT_CAPACITY = 6.5; // Default effective working hours per day per employee
private Long id;
protected String name;
protected String firstname;
protected String account; // references "name" field in Account class
protected String phone;
protected String mobile;
protected String emailAddress;
protected List<Role> roles;
protected boolean isIntern;
protected double capacityPerDay;
protected Team team;
// JPA default constructor
public Employee() {
roles = FXCollections.observableArrayList();
isIntern = true;
}
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
public Long getId() {
return id;
}
@SuppressWarnings("unused") // used by JPA
private void setId(Long id) {
this.id = id;
}
// getter and setter of other fields deleted for brevity
@ManyToOne
@JoinColumn(name = "fk_team")
public Team getTeam() {
return team;
}
public void setTeam(Team newTeam) {
if(team != newTeam) {
team = newTeam;
team.addMember(this);
}
}
@Override
public String toString() {
return getName() + ", " + getFirstname();
}
@Override // taken from Vlad Mihalcea
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Employee )) return false;
return id != null && id.equals(((Employee) o).getId());
}
@Override
public int hashCode() {
return 31;
}
}
和
package com.agiletunes.shared.domain.organization;
import java.io.Serializable;
import java.util.List;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Version;
import com.agiletunes.shared.domain.requirements.UserRequirement;
import com.agiletunes.shared.domain.security.Employee;
import javafx.collections.FXCollections;
@Entity
@Access(AccessType.PROPERTY)
public class Team implements Serializable {
private static final long serialVersionUID = 5479263131702523523L;
private Long id;
private Integer version;
protected String identifier;
protected double capacityPerDay;
protected List<UserRequirement> userRequirements; // the teams backlog
protected List<Employee> members;
// JPA default constructor
public Team() {
userRequirements = FXCollections.observableArrayList();
members = FXCollections.observableArrayList();
}
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
protected Long getId() {
return id;
}
protected void setId(Long id) {
this.id = id;
}
// getter and setter of other fields deleted for brevity
@OneToMany(mappedBy="team")
public List<Employee> getMembers() {
return members;
}
protected void setMembers(List<Employee> newMembers) {
this.members = FXCollections.observableList(newMembers);
}
public void addMember(Employee member) {
if( ! members.contains(member)) {
if(members.add(member)) {
setCapacityPerDay(getCapacityPerDay() + Employee.DEFAULT_CAPACITY);
}
member.setTeam(this);
}
}
public void delMember(Employee member) {
if(members.contains(member)) {
if(members.remove(member)) {
setCapacityPerDay(getCapacityPerDay() - Employee.DEFAULT_CAPACITY);
}
member.setTeam(null);
}
}
@Override
public String toString() {
return identifier;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Team )) return false;
return id != null && id.equals(((Team) o).getId());
}
@Override
public int hashCode() {
return 31;
}
}
此代码导致
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'organizationEntityManagerFactory' defined in class path resource [com/agiletunes/security/OrganizationConfig.class]: Invocation of init method failed; nested exception is org.hibernate.AnnotationException: @OneToOne or @ManyToOne on com.agiletunes.shared.domain.security.Employee.team references an unknown entity: com.agiletunes.shared.domain.organization.Team
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1778)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:593)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean[=14=](AbstractBeanFactory.java:320)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1105)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:742)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:389)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:311)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1213)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1202)
at com.agiletunes.security.AuthServerApp.init(AuthServerApp.java:73)
at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:841)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication9(LauncherImpl.java:182)
at java.lang.Thread.run(Thread.java:748)
Caused by: org.hibernate.AnnotationException: @OneToOne or @ManyToOne on com.agiletunes.shared.domain.security.Employee.team references an unknown entity: com.agiletunes.shared.domain.organization.Team
at org.hibernate.cfg.ToOneFkSecondPass.doSecondPass(ToOneFkSecondPass.java:97)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processEndOfQueue(InFlightMetadataCollectorImpl.java:1827)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processFkSecondPassesInOrder(InFlightMetadataCollectorImpl.java:1771)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1658)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:287)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:904)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:935)
at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:57)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:365)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:390)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:377)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:341)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1837)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1774)
... 18 common frames omitted
这是什么,我没看到?感谢您的帮助和时间
我会检查您的 LocalContainerEntityManagerFactoryBean
是否真的正确配置为扫描包 com.agiletunes.shared.domain.security
和 com.agiletunes.shared.domain.organization
以查找实体 类。
应该是:
localContainerEntityManagerFactoryBean.setPackagesToScan(
"com.agiletunes.shared.domain.security",
"com.agiletunes.shared.domain.organization");
或:
localContainerEntityManagerFactoryBean.setPackagesToScan(
"com.agiletunes.shared.domain");