Return 延迟初始化此集合时为空集合
Return empty collection when this collection is lazy intitialized
我有这个对象:
实体
@Entity
public class someClass{
private String name;
private String labelKey;
@ManyToMany(cascade = {CascadeType.PERSIST,CascadeType.MERGE}, fetch = FetchType.LAZY)
private Set<Product> products = new HashSet<>();
}
DTO
public class someClass{
private String name;
private String labelKey;
private Set<Product> products = new HashSet<>();
}
我的问题是,当我得到这个对象但产品被延迟初始化时,当我使用 Dozer 将实体映射到 DTO 时,我得到一个 LaziInitializedException,然后我想在我得到延迟初始化的产品时得到它,这个产品将return 空集。
这可能吗?
谢谢你的时间,对不起我的英语,这不是我的母语。
您可以 create/modify 您的 Getter 这样:
public Set<Product> getProducts() {
if (products == null) {
return new HashSet<>();
//or products = new HashSet<>(), but I'm not sure of the side effects as far as database framework is concerned.
}
return products;
}
尝试将您的服务 class 或方法标记为 @Transactional 以让 Spring 处理会话管理。
public class ServiceUsingSomeClass {
final SomeClassRepository someClassRepository;
//Constructor ...
@Transactional
showProducts() {
someClassRepository.findAll();
// Do something with Set<Product>
}
}
如果您只想避免在使用 Dozer 进行 DTO 映射的情况下获取关联,您可以将其配置为忽略源对象中的 products
字段,方法是扩展 DozerConverter
并使用该自定义转换器。
我也觉得也许这意味着你的目标类型真的不需要
products
字段开头,因为您不会填充它。
如果您的代码库中有很多这样的地方,请考虑使用投影来仅获取当前目的所需的属性。
@fella7ena 提出了一个关于@Transactional 的观点,但这实际上是无关的——您仍然可以在事务中遇到 LazyInitializationException。发生这种情况是因为 Hibernate 忘记了 java bean 的持久状态和数据库状态之间的关系。如果您真的想从数据库中获取 products
关联,则必须使用 eager fetchtype(导致 n+1 问题)、批处理或实体图。
正如您在本教程中看到的那样 here 您可以指示 dozer
从映射中排除某些字段。
如果你这样做,推土机将不会调用你的实体class的getProducts
方法,因此不会抛出异常LaziInitializedException
。
同时,因为您的 DTO 对象是用空 HashSet
字段产品初始化的,所以这将保留在 DTO 的末尾。
所以您的要求将起作用,其中您的实体是为产品延迟初始化的,而您的 DTO returns 是一个空列表,同时映射发生在 dozer
.
这是 dozer
的映射器所需的配置。
BeanMappingBuilder mappingExclusion = new BeanMappingBuilder() {
@Override
protected void configure() {
mapping(SomeClassEntity.class, SomeClassDto.class).exclude("products");
}
};
mapper = new DozerBeanMapper();
mapper.addMapping(mappingExclusion);
然后你可以使用它来做如下映射
mapper.map(someClassEntityInstance, someClassDtoInstance);
我有这个对象:
实体
@Entity
public class someClass{
private String name;
private String labelKey;
@ManyToMany(cascade = {CascadeType.PERSIST,CascadeType.MERGE}, fetch = FetchType.LAZY)
private Set<Product> products = new HashSet<>();
}
DTO
public class someClass{
private String name;
private String labelKey;
private Set<Product> products = new HashSet<>();
}
我的问题是,当我得到这个对象但产品被延迟初始化时,当我使用 Dozer 将实体映射到 DTO 时,我得到一个 LaziInitializedException,然后我想在我得到延迟初始化的产品时得到它,这个产品将return 空集。 这可能吗?
谢谢你的时间,对不起我的英语,这不是我的母语。
您可以 create/modify 您的 Getter 这样:
public Set<Product> getProducts() {
if (products == null) {
return new HashSet<>();
//or products = new HashSet<>(), but I'm not sure of the side effects as far as database framework is concerned.
}
return products;
}
尝试将您的服务 class 或方法标记为 @Transactional 以让 Spring 处理会话管理。
public class ServiceUsingSomeClass {
final SomeClassRepository someClassRepository;
//Constructor ...
@Transactional
showProducts() {
someClassRepository.findAll();
// Do something with Set<Product>
}
}
如果您只想避免在使用 Dozer 进行 DTO 映射的情况下获取关联,您可以将其配置为忽略源对象中的 products
字段,方法是扩展 DozerConverter
并使用该自定义转换器。
我也觉得也许这意味着你的目标类型真的不需要
products
字段开头,因为您不会填充它。
如果您的代码库中有很多这样的地方,请考虑使用投影来仅获取当前目的所需的属性。
@fella7ena 提出了一个关于@Transactional 的观点,但这实际上是无关的——您仍然可以在事务中遇到 LazyInitializationException。发生这种情况是因为 Hibernate 忘记了 java bean 的持久状态和数据库状态之间的关系。如果您真的想从数据库中获取 products
关联,则必须使用 eager fetchtype(导致 n+1 问题)、批处理或实体图。
正如您在本教程中看到的那样 here 您可以指示 dozer
从映射中排除某些字段。
如果你这样做,推土机将不会调用你的实体class的getProducts
方法,因此不会抛出异常LaziInitializedException
。
同时,因为您的 DTO 对象是用空 HashSet
字段产品初始化的,所以这将保留在 DTO 的末尾。
所以您的要求将起作用,其中您的实体是为产品延迟初始化的,而您的 DTO returns 是一个空列表,同时映射发生在 dozer
.
这是 dozer
的映射器所需的配置。
BeanMappingBuilder mappingExclusion = new BeanMappingBuilder() {
@Override
protected void configure() {
mapping(SomeClassEntity.class, SomeClassDto.class).exclude("products");
}
};
mapper = new DozerBeanMapper();
mapper.addMapping(mappingExclusion);
然后你可以使用它来做如下映射
mapper.map(someClassEntityInstance, someClassDtoInstance);