Spring MapStruct如何获取懒加载实体字段信息?
问题描述
我有两个存在ManyToOne关联且采用懒加载(FetchType.LAZY)的实体:
@Entity public class Item { private Long id; private String title; @ManyToOne(fetch = FetchType.LAZY) private Category category; } @Entity public class Category { private Long id; private String title; }
同时定义了DTO:
public class ItemDTO { private Long id; private String title; private Long categoryId; }
从数据库获取Item后,使用MapStruct将其映射为ItemDTO,映射规则如下:
@Mapping(source = "category.id", target = "categoryId") ItemDTO itemToItemDTO(Item item);
一切运行正常,但我有个疑问:MapStruct在其实现类中是如何以及从何处获取懒加载的category的信息?我已在配置中开启show-sql: true,但映射时并未看到额外的SQL查询,能否解释其工作原理?
原理解释
- Hibernate懒加载代理的特性:当通过JPA加载
Item时,因为category是懒加载关联,Hibernate不会直接查询并实例化真实的Category对象,而是返回一个动态生成的代理类对象(比如Category$HibernateProxy)。这个代理对象会持有关联实体的id值(来自Item表中存储的外键),但不会加载Category的其他属性。 - MapStruct的直接调用逻辑:MapStruct生成的实现类代码,本质就是直接调用
item.getCategory().getId()。而调用代理对象的getId()方法时,不需要触发懒加载——因为代理对象本身已经保存了这个外键值,无需去数据库查询完整的Category实体。 - 为什么没有额外SQL:只有当调用代理对象的其他非
getId类方法(比如getTitle())时,Hibernate才会触发懒加载查询,去数据库拉取完整的Category数据。而这里只获取id,完全不需要触发数据库操作,所以show-sql不会输出额外查询语句。
你可以做个简单验证:打印item.getCategory().getClass(),会看到输出的是Hibernate的代理类而非真实的Category类;如果把映射规则改成source = "category.title",此时就会触发懒加载,show-sql就能看到对应的查询语句了。
内容的提问来源于stack exchange,提问作者Nicenick
相关产品推荐
相关产品推荐

