我已经使用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)一起工作,但是由于实体具有数据库注释并且数据库是基础结构问题,因此我的核心将变得肮脏。
我的问题是:如何既保持性能又保持核心干净?