Java Springboot JPA/hibernate:如何将一个表映射到多个实体

Java Springboot JPA/hibernate:如何将一个表映射到多个实体,java,spring,hibernate,jpa,spring-boot,Java,Spring,Hibernate,Jpa,Spring Boot,我正在创建一个系统,在这个系统中,我有一些实体,它们有一些公共属性,比如地址(带有街道、号码、邮编等)和电话(号码、类型等),我不想在每个实体上重复这些列 这里有一个例子: 学生有地址和电话 老师有多个地址(家) 和办公室)和多部电话(家庭、手机、办公室) 员工 有地址和多部电话(家庭、手机和办公室) 我在使用多态关联开发RubyonRails时使用过类似的东西。我在Java/JPA/Hibernate上搜索过类似的东西,但找不到类似的东西。我发现了很多关于JPA继承的东西,但我不太了解它

我正在创建一个系统,在这个系统中,我有一些实体,它们有一些公共属性,比如地址(带有街道、号码、邮编等)和电话(号码、类型等),我不想在每个实体上重复这些列

这里有一个例子:

  • 学生有地址和电话
  • 老师有多个地址(家) 和办公室)和多部电话(家庭、手机、办公室)
  • 员工 有地址和多部电话(家庭、手机和办公室)
我在使用多态关联开发RubyonRails时使用过类似的东西。我在Java/JPA/Hibernate上搜索过类似的东西,但找不到类似的东西。我发现了很多关于JPA继承的东西,但我不太了解它

你能给我一个关于如何建模和如何使用它的例子吗

编辑

阅读完我的问题后,我认为还不够清楚,所以让我在这里添加我的数据库模式:

Student
-------
id bigint
name varchar
birth_date date
...

Teacher
-------
id bigint
name varchar
birth_date date
department varchar
...

StaffMember
-------
id bigint
name varchar
birth_date date
department varchar
function varchar
...

Address
-------
id bigint
street varchar
number int
...
entity_id bigint
entity_type varchar

Phone
-----
id bigint
type varchar
number varchar
...
entity_id bigint
entity_type varchar
对于
地址
电话
,列
实体id
实体类型
都是对
学生
教师
员工
的引用


但是如何使用Hibernate/JPA映射它呢?

我认为您需要的是使用一个通用的存储库类


这篇文章解释了很多。请告诉我是否适合您。

以下内容:

   @Embeddable
   public class Address {
        // Fields & accessors
        // Do the Phone class in similar fashion
   }

   @Entity
   @DiscriminatorColumn(name = "entity_type")
   public abstract class Person {
        @Id
        private Integer id;

        private String name;

        @Embedded 
        private Address homeAddress;

        @Embedded 
        private Phone homePhone;

       // Other shared fields & accessors

   }

   @Entity
   public abstract class Employee extends Person {

        @Embedded 
        private Phone mobilePhone;

        @Embedded 
        private Phone officePhone;

       //...

    }

    @Entity
    public class Students extends Person {

    }

    @Entity
    public class StaffMember extends Employeee {

    }

    @Entity
    public class Teacher extends Employeee {

      @Embedded
      private Address officeAddress;

      // Accessors & other ...
   }

如果您不介意使用特定于Hibernate的注释,那么可以使用和注释来实现您想要的功能。您需要为每个与地址相关的实体类型指定一个条目,以便Hibernate知道如何存储项类型的正确值

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;

import org.hibernate.annotations.Any;
import org.hibernate.annotations.AnyMetaDef;
import org.hibernate.annotations.MetaValue;

@Entity
public class Address {

    @Any(metaColumn = @Column(name = "ITEM_TYPE"))
    @AnyMetaDef(idType = "long", metaType = "string",
            metaValues = {
                    @MetaValue(targetEntity = Student.class, value = "STUDENT"),
                    @MetaValue(targetEntity = Teacher.class, value = "TEACHER")
            })
    @JoinColumn(name="ITEM_ID")
    private Object item;

    @Id
    @GeneratedValue
    private Long id;

    @Column
    private String type;

    @Column
    private String street;

    @Column
    private int number;

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getStreet() {
        return street;
    }

    public void setStreet(String street) {
        this.street = street;
    }

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }


    public Object getItem() {
        return item;
    }

    public void setItem(Object item) {
        this.item = item;
    }

    @Override
    public String toString() {
        return "Address{" +
                "person=" + item +
                ", id=" + id +
                ", type='" + type + '\'' +
                ", street='" + street + '\'' +
                ", number=" + number +
                '}';
    }
}
现在,您可以在任何具有适当@MetaValue条目的bean中使用Address,这两个条目都是@ManyToOne关联:

@ManyToOne
protected Address address;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
protected Collection<Address> addresses;
或@OneToMany协会:

@ManyToOne
protected Address address;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
protected Collection<Address> addresses;
@OneToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER)
受保护的收集地址;

我使用SpringBoot创建了一个简单的测试项目,它似乎工作得很好

请确定:您的数据库模式是固定的,JPA/hibernate必须对其进行调整吗?Hi@larsgrefer,不,该模式足够灵活,上面只是一个它认为最好的示例,但我愿意接受建议。当您使用spring boot时,只需设置
spring.jpa.generate ddl=true
,让hibernate为youHi@Nicolas Fontenele生成模式,这并不是我想要的(或者我解释错了)。我已经在我的问题中添加了更多的细节,所以它可能会帮助您更好地理解。无论如何,谢谢。Hi@dev null通过使用嵌入式,我可以将地址存储在单独的表中吗?我不想在数据库中的每个表上复制这个结构,@embeddeble的要点是它没有特殊的表,只是嵌入到其他表中的数据结构。类似复合数据类型的东西。谢谢@João Marcus,这正是我想要的!请解释“.它有正确的@MetaValue条目”。通过这种方式,我得到了从
学生
地址
的单向
@OneToMany
关系,由于缺少无法定义的
mappedBy
属性,它创建了一个额外的
学生地址
教师地址
表。我怎样才能避免呢?