我正在创建一个与办公室打交道的Spring JPA(PostgresSQL和H2)服务。我可以有一个独立的办公室,也可以有一个带孩子(远程)办公室的母公司(公司)。办公室有一个地址和一个雇员列表(他们可以属于多个办公室)。我正在努力设计,非常感谢您能提供的任何帮助。

我的表当前在H2中以进行测试/开发,因此表上没有任何参照完整性。
这让我想知道我的模型是否无法改进。有没有更好的方法来进行这种递归/嵌套关系?

更新
基于jfneis的出色反馈,我现在采用以下方法:

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "OfficeType")
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "officeId")
public abstract class Office {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "officeId", updatable = false, nullable = false)
    private long officeId;

    @Column
    private String name;
    @Column
    private String ein;
    @Column
    @Temporal(TemporalType.DATE)
    private Date startDate;
    @Column
    @Temporal(TemporalType.DATE)
    private Date endDate;

    @OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinColumn(name = "addressId", nullable = false)
    private Address address;

    @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @Fetch(value = FetchMode.SUBSELECT)
    private List<Employee> employees = new ArrayList<>();
}


和公司办公室:

@Entity(name = "CorporateOffice")
@DiscriminatorValue("Corporate")
public class CorporateOffice extends Office {

    @Column
    private String url;
}


和远程办公室:

@Entity(name = "RemoteOffice")
@DiscriminatorValue("Remote")
public class RemoteOffice extends Office {

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "corporateOfficeId")
    private Office corporateOffice;
}


如果我理解正确,这两种办公室类型都将存储在“办公室”表中,并带有一列指示其类型。

在启动时,我正在播种一些测试数据,以便可以进一步了解发生了什么:

@Component
@Transactional
public class SeedOffices {

@Autowired
private OfficeRepository officeRepository;

@PostConstruct
public void seedOffices() {
    CorporateOffice corporate = new CorporateOffice();
    corporate.setName("World Domination Corp");
    corporate.setUrl("www.corporationsownstheworld.com");
    corporate.setStartDate(new Date());
    Address corpAddr = new Address();
    corpAddr.setAddressLine1("corp line 1");
    corpAddr.setCity("Denver");
    corporate.setEin("123456789");
    corporate.setAddress(corpAddr);
    officeRepository.save(corporate);

    RemoteOffice office1 = new RemoteOffice();
    office1.setStartDate(new Date());
    Address remote1Addr = new Address();
    remote1Addr.setAddressLine1("remote 1 line 1");
    remote1Addr.setCity("Cheyanne");
    office1.setAddress(remote1Addr);
    officeRepository.save(office1);
    office1.setCorporateOffice(corporate);

    RemoteOffice office2 = new RemoteOffice();
    Address remote2Addr = new Address();
    remote2Addr.setAddressLine1("remote 2 line 1");
    remote2Addr.setCity("Calumet");
    office2.setAddress(remote2Addr);
    officeRepository.save(office2);
    office2.setCorporateOffice(corporate);
}


}

最佳答案

这是一个带有主观答案的设计问题(不是SO应该回答的那种答案)。

无论如何:我不喜欢单一的Office课程。对于两种不同的行为,您只有一个班级:公司办公室(可以具有远程办公室)和远程办公室(可以具有母办公室)。

在这两点中都保留引用符合您的业务需求,但是我的建议是:拥有一个具有通用属性的抽象类Office,以及2个子类:CorporateOffice和RemoteOffice,它们各自处理所需的属性。

您可以使用“单表”策略将两者映射到同一表中。要获得有关JPA子类化策略的非常好的文章,请查看this article



编辑:回答有关RemoteOffice映射的第二个问题:

我相信您的RemoteOffice映射是错误的。您将CorporateOffice声明为@OneToMany,但实际上是@ManyToOne关系,不是吗?请在此字段中测试@ManyToOne + @JoinColumn,以检查是否解决了您的问题。

关于java - 嵌套的 hibernate 实体,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/45820093/

10-12 04:44