如何使用JPA既保持性能又保持核心干净?

时间:2018-07-27 18:47:54

标签: java hibernate spring-data-jpa domain-driven-design onion-architecture

我已经使用Spring Data JPA已有一段时间了。我也一直在需要的项目中应用Onion Architecture。我正在创建一个同时应用Spring Data JPA和Onion Architecture的项目,但是在这次冒险中,我偶然遇到了一个问题,希望你们能够帮助我解决。

我有实体“ PanelEntity”:

@Entity
@Table(name = "panel")
public class PanelEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", unique = true, nullable = false)
    private Integer id;

    @Column(name = "description")
    private String description;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "manufacturer_id")
    private ManufacturerEntity manufacturer;

    /* getters and setters */
}

我在核心中有DTO“ Panel”,代表“ PanelEntity”:

public class Panel {
    private int id;
    private String description;
    private Manufacturer manufacturer;

    /* getters and setters */
}

由于我非常在意性能,因此我只会加载操作所需的实体集。因此,“ PanelEntity”的存储库方法如下:

@Override
public Panel findByIdMinimal(Integer id) {
    TypedQuery<PanelEntity> query =
            em.createQuery(
                    "select p from PanelEntity p " +
                            "where p.id = :id", PanelEntity.class)
                    .setParameter("id", id);

    return new JpaModelMapper(em, mapper).mapQuery(query, Panel.class).getSingleResult();
}

@Override
public Panel findByIdWithManufacturer(Integer id) {
    TypedQuery<PanelEntity> query =
            em.createQuery(
                    "select p from PanelEntity p " +
                            "join fetch p.manufacturer m " +
                            "where p.id = :id", PanelEntity.class)
                    .setParameter("id", id);

    return new JpaModelMapper(em, mapper).mapQuery(query, Panel.class).getSingleResult();
}

'findByIdMinimal'方法选择实体而不加载任何关联的实体。

'findByIdWithManufacturer'方法选择加载制造商关联实体的实体。

下面的代码是ModelMapperJPA的一部分。它基本上执行我的查询,并使用ModelMapper将结果“ PanelEntity”映射到“ Panel” DTO。它还为所有未加载的实体(标记为延迟加载且未加入获取)设置了null。

return new JpaModelMapper(em, mapper).mapQuery(query, Panel.class).getSingleResult();

直到现在一切正常。例如,如果要获取面板说明,则将其称为“ findByIdMinimal”。如果我想让面板带有一些制造商信息,我会称其为“ findByIdWithManufacturer”。

现在,让我们假设我有以下方法:

public void someBussinessLogic(Integer panelId) {
    // Gets only the PanelEntity without its associated entities
    Panel panel = panelRepository.findByIdMinimal(panelId);

    // Changes the description
    panel.setDescription("New Panel Description");

    // Saves back the changes
    panelRepository.save(panel);
}

我的保存方法会将“ Panel”映射到“ PanelEntity”,然后将其保存:

@Override
public void save(Panel panel) {
    PanelEntity entity = mapper.map(panel, PanelEntity.class);
    panelDao.save(entity);
}

制造商会发生什么? 答:因为我没有加载它,它将被设置为null。

我总是可以热切地获取我的实体,但这会破坏我的应用程序的性能。我也可以直接与实体(不带DTO)一起工作,但是由于实体具有数据库注释并且数据库是基础结构问题,因此我的核心将变得肮脏。

我的问题是:如何既保持性能又保持核心干净?

0 个答案:

没有答案