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.securitycom.agiletunes.shared.domain.organization 以查找实体 类。

应该是:

localContainerEntityManagerFactoryBean.setPackagesToScan(
"com.agiletunes.shared.domain.security", 
"com.agiletunes.shared.domain.organization");

或:

  localContainerEntityManagerFactoryBean.setPackagesToScan(
    "com.agiletunes.shared.domain");