JPA命名查询中的多对一关系

Posted

技术标签:

【中文标题】JPA命名查询中的多对一关系【英文标题】:ManyToOne Relation in JPA namedQuery 【发布时间】:2017-01-20 03:30:32 【问题描述】:

我是 JPA 的新手,现在研究如何通过 manytoone 关系连接两个表。我得到的实体来自数据库。我有两个表,分别命名为 Department 和 Employee。许多员工属于一个部门。

部门

@Entity
@Table(name = "DEPARTMENT")
@XmlRootElement
@NamedQueries(
    @NamedQuery(name = "Department.findAll", query = "SELECT d FROM Department d")
    , @NamedQuery(name = "Department.findById", query = "SELECT d FROM Department d WHERE d.id = :id")
    , @NamedQuery(name = "Department.findByName", query = "SELECT d FROM Department d WHERE d.name = :name"))
public class Department implements Serializable 

    private static final long serialVersionUID = 1L;
    @Id
    @Basic(optional = false)
    @Column(name = "ID")
    private Integer id;
    @Column(name = "NAME")
    private String name;
    @OneToMany(mappedBy = "departmentId")
    private Collection<Employee> employeeCollection;

    public Department() 
    

    public Department(Integer id) 
        this.id = id;
    

    public Integer getId() 
        return id;
    

    public void setId(Integer id) 
        this.id = id;
    

    public String getName() 
        return name;
    

    public void setName(String name) 
        this.name = name;
    

    @XmlTransient
    public Collection<Employee> getEmployeeCollection() 
        return employeeCollection;
    

    public void setEmployeeCollection(Collection<Employee> employeeCollection) 
        this.employeeCollection = employeeCollection;
    

    @Override
    public int hashCode() 
        int hash = 0;
        hash += (id != null ? id.hashCode() : 0);
        return hash;
    

    @Override
    public boolean equals(Object object) 
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof Department)) 
            return false;
        
        Department other = (Department) object;
        if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) 
            return false;
        
        return true;
    

    @Override
    public String toString() 
        return "entity.Department[ id=" + id + " ]";
    


员工

@Entity
@Table(name = "EMPLOYEE")
@XmlRootElement
@NamedQueries(
    @NamedQuery(name = "Employee.findAll", query = "SELECT e FROM Employee e")
    , @NamedQuery(name = "Employee.findByEid", query = "SELECT e FROM Employee e WHERE e.eid = :eid")
    , @NamedQuery(name = "Employee.findByDeg", query = "SELECT e FROM Employee e WHERE e.deg = :deg")
    , @NamedQuery(name = "Employee.findByEname", query = "SELECT e FROM Employee e WHERE e.ename = :ename")
    , @NamedQuery(name = "Employee.findBySalary", query = "SELECT e FROM Employee e WHERE e.salary = :salary"))
public class Employee implements Serializable 

    private static final long serialVersionUID = 1L;
    @Id
    @Basic(optional = false)
    @Column(name = "EID")
    private Integer eid;
    @Column(name = "DEG")
    private String deg;
    @Column(name = "ENAME")
    private String ename;
    // @Max(value=?)  @Min(value=?)//if you know range of your decimal fields consider using these annotations to enforce field validation
    @Column(name = "SALARY")
    private Double salary;
    @JoinColumn(name = "DEPARTMENT", referencedColumnName = "ID")
    @ManyToOne
    private Department department;

    public Employee() 
    

    public Employee(Integer eid) 
        this.eid = eid;
    

    public Integer getEid() 
        return eid;
    

    public void setEid(Integer eid) 
        this.eid = eid;
    

    public String getDeg() 
        return deg;
    

    public void setDeg(String deg) 
        this.deg = deg;
    

    public String getEname() 
        return ename;
    

    public void setEname(String ename) 
        this.ename = ename;
    

    public Double getSalary() 
        return salary;
    

    public void setSalary(Double salary) 
        this.salary = salary;
    

    public Department getDepartment() 
        return department;
    

    public void setDepartment(Department department) 
        this.department = department;
    

    @Override
    public int hashCode() 
        int hash = 0;
        hash += (eid != null ? eid.hashCode() : 0);
        return hash;
    

    @Override
    public boolean equals(Object object) 
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof Employee)) 
            return false;
        
        Employee other = (Employee) object;
        if ((this.eid == null && other.eid != null) || (this.eid != null && !this.eid.equals(other.eid))) 
            return false;
        
        return true;
    

    @Override
    public String toString() 
        return "entity.Employee[ eid=" + eid + " ]";
    

多对一

public class ManyToOne 

    public static void main(String[] args) 
        EntityManagerFactory emfactory = Persistence.
                createEntityManagerFactory("JoinTablePU");
        EntityManager entitymanager = emfactory.
                createEntityManager();
        entitymanager.getTransaction().begin();

        //Create Department Entity
        Department department = new Department();
        department.setName("Development");
        //Store Department
        entitymanager.persist(department);

        //Create Employee1 Entity
        Employee employee1 = new Employee();
        employee1.setEname("Satish");
        employee1.setSalary(45000.0);
        employee1.setDeg("Technical Writer");
        employee1.setDepartment(department);

        //Create Employee2 Entity
        Employee employee2 = new Employee();
        employee2.setEname("Krishna");
        employee2.setSalary(45000.0);
        employee2.setDeg("Technical Writer");
        employee2.setDepartment(department);

        //Create Employee3 Entity
        Employee employee3 = new Employee();
        employee3.setEname("Masthanvali");
        employee3.setSalary(50000.0);
        employee3.setDeg("Technical Writer");
        employee3.setDepartment(department);

        //Store Employees
        entitymanager.persist(employee1);
        entitymanager.persist(employee2);
        entitymanager.persist(employee3);

        entitymanager.getTransaction().commit();
        entitymanager.close();
        emfactory.close();
    

错误

Exception Description: The attribute [employeeCollection] in entity class [class entity.Department] has a mappedBy value of [departmentId] which does not exist in its owning entity class [class entity.Employee]. If the owning entity class is a @MappedSuperclass, this is invalid, and your attribute should reference the correct subclass.
    at org.eclipse.persistence.exceptions.PersistenceUnitLoadingException.exceptionSearchingForPersistenceResources(PersistenceUnitLoadingException.java:127)
    at org.eclipse.persistence.jpa.PersistenceProvider.createEntityManagerFactoryImpl(PersistenceProvider.java:107)
    at org.eclipse.persistence.jpa.PersistenceProvider.createEntityManagerFactory(PersistenceProvider.java:177)
    at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:79)
    at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:54)
    at jointable.ManyToOne.main(ManyToOne.java:22)

【问题讨论】:

【参考方案1】:

应该是

@OneToMany(mappedBy = "department")
    private Collection<Employee> employeeCollection;

mappedBy = "department" 属性指定 Employee 中的 private Department department; 字段拥有 关系(即包含查询的外键 查找部门的所有员工。

在这里你可以找到类似的example

【讨论】:

【参考方案2】:

mappedBy 属性用于表示双向关系中的逆字段。它标识employeeCollection 将在从数据库中检索部门实体时自动填充。 在你的情况下,它应该是mappedBy = department

查看this 链接以查找形成双向关系的员工-部门模型的准确表示及其详细描述。

【讨论】:

以上是关于JPA命名查询中的多对一关系的主要内容,如果未能解决你的问题,请参考以下文章

MyBatis之多对一关系

如何正确映射与@IdClass 的多对一关系?

Hibernate 多对一关联查询

django--ORM表的多对一关系

重复条目异常:Spring Hibernate/JPA 级联保存多对一

如何使用 jpa 存储库查询多对一映射