在我们的Restful应用程序中,我们决定使用DTO来屏蔽Hibernate域模型,原因有几个。
我们使用DTOMappers
中的Service Layer
手动将Hibernate实体映射到DTO,反之亦然。
服务层中的示例:
@Transactional(readOnly=true)
public PersonDTO findPersonWithInvoicesById(Long id) {
Person person = personRepository.findById(id);
return PersonMapperDTOFactory.getInstance().toDTO(person);
}
主要概念可以这样解释:
JSON (Jackson parser) <-> Controller <-> Service Layer (uses Mapping Layer) <-> Repository
我们同意通过使用HQL
执行Criteria
(或left join
)来检索关联。
这主要是一种检索关系并避免使用N+1 select issue
的高效方法。
但是,当开发人员错误地忘记进行左连接时,仍然可以拥有N+1 select issue
。仍将提取关系,因为PersonDTOMapper
会迭代Invoices
的{{1}}以转换为Person
。因此,仍然会获取数据,因为执行InvoiceDTOs
Hibernate会话处于活动状态(由DTOMapper
管理)
是否有某种方法可以使Spring
&#39;不活跃&#39;在我们的Hibernate Session
?我们将面临一个DTOMappers
,它应该触发开发人员,他没有像我们那样获取某些数据。
我已阅读暂停交易的LazyInitializationException
。但是,我不知道它是出于这种目的。
实现这一目标的清洁解决方案是什么?替代品也非常受欢迎!
答案 0 :(得分:0)
通常我在控制器层使用映射器。从我的角度来看,服务层管理应用程序业务逻辑,如果您想以不同的方式将数据呈现给外部世界,则dtos非常有用。通过这种方式,你可能会得到你正在寻找的懒惰的inizitalization excpetion。
我还有一个理由更喜欢这个解决方案:只需要在服务类的公共方法中调用公共方法的图像:在这种情况下,您可能需要多次调用映射器。
答案 1 :(得分:0)
如果您正在使用Hibernate,那么有一些特定的方法可以确定关联对象是否已延迟加载。
例如,假设您有一个实体类Foo
,它包含与实体类@ManyToOne
的{{1}}'外来'关联,由Bar
中的字段表示叫Foo
。
在您的DTO映射代码中,您可以使用以下代码检查关联的bar
是否已延迟加载:
bar
答案 2 :(得分:0)
实现所需目标的最简单解决方案是在查询之后和调用DTO映射器之前清除实体管理器。这样,该对象将被分离,并且对未初始化的关联的访问将触发LazyInitializationException
。
我也感到很痛苦,这促使我开发了Blaze-Persistence Entity Views,它允许您将DTO定义为接口,并使用属性名称作为默认映射来映射到实体模型,该映射允许非常简单的映射。 / p>
这里有个例子
@Entity
class Person {
@Id Long id;
String name;
String lastName;
String address;
String city;
String zipCode;
}
@EntityView(Person.class)
interface PersonDTO {
@IdMapping Long getId();
String getName();
}
查询就像
@Transactional(readOnly=true)
public PersonDTO findPersonWithInvoicesById(Long id) {
return personRepository.findById(id);
}
interface PersonRepository extends EntityViewRepository<PersonDTO, Long> {
PersonDTO findById(Long id);
}
由于您似乎正在使用Spring数据,因此您会喜欢spring data integration。