我有父级(产品)和子级(书籍、家具),并希望将产品实体Map到产品dto。如您所见,产品被Map并存储在数据库的单个表中。我如何Map父产品,它有子产品的额外细节?
我看了这个,这个和这个想知道些什么,但是运气不好
实体
@Entity
@Table(name = "product")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class Product {
@Id
private long id;
private String productName;
}
@Entity
@DiscriminatorValue("Book")
public class Book extends Product {
private String author;
...
}
@Entity
@DiscriminatorValue("Furniture")
public class Furniture extends Product {
String color;
...
}
dto公司
public class ProductDto {
private long id;
private String productName;
...
}
public class BookDto extends ProductDto {
private String author;
...
}
public class FurnitureDto extends ProductDto {
String color;
...
}
制图器
@Mapper(uses = {BookMapper.class,FurnitureMapper.class})
public interface ProductMapper {
ProductDto productToProductDto(Product product);
Product productDtoToProduct(ProductDto productDto);
}
@Mapper
public interface BookMapper {
BookDto bookToBookDto(Book book);
Book bookDtoToBook(BookDto bookDto);
}
@Mapper
public interface FurnitureMapper {
FurnitureDto furnitureToFurnitureDto(Furniture furniture);
Furniture furnitureDtoToFurniture(FurnitureDto furnitureDto);
}
服务
@Service
public class ProductServiceImpl implements ProductService {
@Autowired
ProductRepository productRepository;
@Autowired
ProductMapper productMapper;
@Override
public List<ProductDto> getAllProducts() {
List<ProductDto> listOfProducts = new ArrayList<>();
productRepository.findAll().forEach(i ->
listOfProducts.add(productMapper.productToProductDto(i)));
return listOfProducts;
}
}
编辑
在将产品实体Map到产品dto之后,我得到以下结果。它不绑定数据,也不包含其子属性。上面的Map器部分正确吗?
[
{
"id": 0,
"productName": null
},
{
"id": 0,
"productName": null
},
...
]
然而,结果应该如下:
[
{
"id": 11,
"productName": ABC,
"author":"James"
},
{
"id": 22,
"productName": XYZ,
"color":"Oak"
},
...
]
2条答案
按热度按时间ubof19bj1#
这与本期中描述的场景完全相同。
不幸的是,这个问题目前仍然悬而未决,到目前为止还没有人提供解决方案。所以我认为你想要的是不可能的。
解决问题的唯一方法是更改服务中的代码。
正如本期所提到的,你可以做的一件事就是测试每个
Product
对象instanceof
:你也可以让你的
ProductMapper
延伸BookMapper
以及FurnitureMapper
,所以你不必注射。ekqde3dh2#
热释光;博士
没有干净的方法可以做到这一点。原因在于java的编译时方法选择。但是有一种使用visitor模式的干净方法。
为什么不起作用
迭代包含不同类型(产品、书籍、家具)的实体列表时,需要为每个类型调用不同的Map方法(即不同的mapstructMap器)。
除非你同意
instanceof
正如amir所建议的那样,如果要显式地选择Map器,则需要使用方法重载来为每个实体类调用不同的Map方法。问题是java将在编译时选择重载方法,此时编译器只看到Product
对象(存储库方法返回的对象)。如果mapstruct、spring或您自己的自定义代码尝试这样做,其实并不重要。这也是为什么你ProductMapper
总是调用:它是编译时唯一可见的类型。使用访问者模式
因为我们需要手动选择正确的Map器,所以我们可以选择哪种方式更干净或更易于维护。这绝对是有意见的。
我的建议是按以下方式使用访问者模式(实际上是其变体):
为需要Map的实体引入新接口:
您的实体将需要实现此接口,例如:
entitymapper是访问者界面:
最后,您需要主Map器:
您的服务方法将如下所示:
你完全可以忽略
Mappers.getMapper()
调用:由于这个问题与spring无关,为了简单起见,我使用mapstruct的工厂在github上创建了一个工作示例。您只需使用cdi注入Map器。