当前位置: 首页 > 知识库问答 >
问题:

在Hibernate会话之外执行Mapstruct映射

轩辕瑞
2023-03-14
public class VacancyEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Integer id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "job_category_id", nullable = false)
    JobCategoryEntity jobCategory;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "company_id", nullable = false)
    CompanyEntity company;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "employer_created_by", nullable = false)
    EmployerProfileEntity employerCreatedBy;

    @Column(nullable = false)
    String title;
.... }
public class VacancyDto {

    Integer id;

    String title;

    CompanyDto company;

    EmployerProfileDto employerCreatedBy;

    JobCategoryDto jobCategory;

    ...} 

因此,我在VacancyRepository中有两个方法FindByIdWithCompanyandCityFindByIdWithJobandCityAndEmploymente,只执行一个SQL请求。

和我的VacancyService中的两个@Transaction方法:FindWithCompanyandCityFindWithCompanyandCityandEmployment

最佳实践是从服务层返回Dto,因此我们需要将实体解析为服务中的Dto。

我真的不想把整个映射留在@transactional(session),因为如果我在实体中添加一些字段,那么Mapstruct只会触发N+1个问题。

我想出的最好方法是将每个内部实体包含到方法中,并手动检查Mapstruct是否添加了一些新方法。(它比检查名字更快)例如:

    @Mapping(target = "id", source = "entity.id")
    @Mapping(target = "description", source = "entity.description")
    @Mapping(target = "jobCategory", source = "jobCategoryDto")
    @Mapping(target = "employerCreatedBy", source = "employerProfileDto")
    @Mapping(target = "city", source = "cityDto")
    @Mapping(target = "company", ignore = true)
    VacancyDto toDto(VacancyEntity entity,
                     JobCategoryDto jobCategoryDto,
                     EmployerProfileDto employerProfileDto,
                     CityDto cityDto);
   ....

但这并不能解决真正的问题。映射时仍然存在会话,因此会导致N+1问题。

    null

我知道在这两种情况下我都会得到LazyInitializationException,但在我看来,它比不可预测的select更健壮、更可伸缩。

如何以优雅的方式在服务层但在Hibernate会话之外执行从实体到DTO的映射?

共有1个答案

田意致
2023-03-14

你没有问一个问题,但似乎这个问题应该是:

如何以优雅的方式在服务层但在Hibernate会话之外执行从实体到DTO的映射。

为此,我建议使用TransactionTemplate。用法如下所示:

@Autowired 
VacancyRepository repo;

@Autowired
TransactionTemplate tx;

void someMethod(String company, String city){

    VacancyEntity vac = tx.execute(__ -> repo.findWithCompanyAndCity(company, city));
    
    return mappToDto(vac);
}
 类似资料:
  • 我对这些技术是新的,所以提前道歉。 我在我的应用程序中使用了springboot、Spring JPA、hibernate和mapstruct。

  • 我在学习冬眠时遇到了一个问题。我写了UnitTest和那里我尝试添加对象到DB。所有选择都正常工作,但插入不正常。 我也尝试过这样的东西 它引发了一个异常,事务没有成功启动,但它添加了用户 这里有一个例外 组织。springframework。交易TransactionSystemException:无法回滚Hibernate事务;嵌套的异常是org。冬眠TransactionException:

  • 我指的是https://developer.jboss.org/wiki/SessionsAndTransactions,目前正试图了解与JTA的划界问题。它声明在使用getCurrentSession()的特定事务中,总是给出相同的当前会话。是不是意味着: < li >如果另一个用户在另一个线程中执行同一段代码(通过查找获取一个事务,然后使用getCurrentSession()并关闭该事务),

  • 我有两个方法,它们都被注释为@Transactional。 我知道这两种方法将在两个不同的事务中执行。 但是这两个方法是在一个Hibernate会话中执行吗? spring事务管理器将会话保持到http请求结束。 我知道事务管理器可能会在它的 aop 代理中执行类似操作: 我只是找不到代码,如果我能在某处找到代码,我可以自己回答这个问题。

  • 我找了很多解决办法。谢了。

  • 问题内容: 我是Spring框架的初学者。 在我的情况下,会话可以通过以下方式过期 ->成功注销(显式注销) ->会话超时(隐式注销) 每当某些用户登录时,我都会在数据库中执行DML(记录插入),并且每当用户会话超时(隐式注销)时,我都希望在数据库中执行DML(记录删除)。 我的问题是,春季会议期间有什么办法告诉我们。因此,我可以在会话到期前执行自定义事件。 提前致谢 问题答案: 是的,您可以使用