为ORM域图设计JPARepository的最佳实践

时间:2017-07-25 14:52:11

标签: java spring hibernate jpa

我一直在使用标准MVC架构(如域层)作为POJO和存储库来设计spring rest apis,以从db表中获取域数据。到目前为止,这些实体是隔离的,因此设计作为每个实体的独立RestController,Service和Repository流程。 我一直在寻找理解域对象中关联的最佳实践,即ORM。例如,让我们使用下面的伪代码来说明域类(仅用于表达有问题的设计。我没有提供完整的类):

public class Customer {
    @Column
    private int id;

    @Column;
    private String name;

    @OneToMany
    private List<Order> orders;

    //...getters setters
}

public class Order {
    @Column
    private int id;

    @Column;
    private String orderNumber;

    @OneToMany
    private List<Product> products;

    @ManyToOne
    private Customer customer;

    //...getters setters
}

 public class Product {
    @Column
    private int id;

    @Column;
    private String productName;

    @ManyToOne
    private Order order;

    //...getters setters
}

从设计角度看我遇到的困境。我有以下几种方法都是错误的:

  1. 为客户定义一个RestController,并提供所有api资源,如/ customers,/ customers / id / orders,/ customers / id / orders / id / products等。有一个服务负责处理这些域。为EACH域分别拥有JPARepository。这里的“保持简单”是我为每个域都有separete存储库所以我只需要在相应的Repository类中提供查询方法,以便查找特定域的详细信息,即获取给定客户Id的订单。然而,这让我想到了使用ORM模型的目的,因为我通过他们的Repository类获取单个域。此选项将使所有3个存储库类在服务类中连接,而且我认为这也不是一个好的设计。 3可能在这里看起来不错,但我在实际要求中的ORM图中有6到7个域,这意味着在一个服务类中自动装配6个repositoris。

  2. 一个RestController和一个Service类,如上面的选项,但Repository类也是单一的。仅为Customer域创建存储库。通过这种方式,我检索了与其他domaims延迟加载的客户。这是为了满足“/ customers”的GET请求。为了满足“/ customers / id / orders”的GET请求,我将再次使用Customer Repository,检索给定Id的客户,然后返回订单列表。此外,对于“/ customers / id / orders / id / products”的GET请求,我将要求在Customer域中编写手动数据提取机制,以便它负责检索给定customerId和orderId的产品列表。这样我使用一个Repository,满足了使用ORM的目的,但随后在Customer域中添加了手动获取数据方法。我看到的另一个负面因素是,即使我有customerId和orderId,我也需要在客户域中获得完整的订单列表。我会根据customerId获取一个单一的订单,而orderId我已经为Order使用了一个单独的存储库。

  3. 两者都不正确,并且存在更好的方法。

  4. 我已经通过spring docs查看了ORM的存储库和hibernate文档。我通过多个教程进行了一对多的映射,其中包含了spring数据,但我在不同的教程中找到了混合方法。

    这个问题对你来说很重要,因为我已经在stackoverflow上阅读了关于这个设计问题的多篇帖子,但没有一个答案给我一个推理我上面提到的权衡和选项。因此,我正在重新提出这个问题。

1 个答案:

答案 0 :(得分:0)

这是一种混合方法。例如在您的情况下,产品实体不需要与订单具有@ManyToOne关系。想象一下,如果您的产品是100万订单的一部分!您会在多长时间内查询产品以查找订单?您将查询findOrdersByProduct(Product)而不是findProductByOrder(Order)

  1. 想想你的用例。如果您永远不会从关系所有者那里获取信息,那么有时候有一个方向映射是有意义的

  2. 如果查询实体,请考虑要获取的数据量(包括连接数)。

  3. 例如,如果我要获取组织,我是否需要获取其所有员工?你的系统将进行折腾(延迟加载将节省你的大部分时间,但如果你有一个Angular,那么它将绑定并获取整个模型)。但是与员工实体的组织建立多对一的关系确实有意义。