Mapstruct:加入id
Mapstruct: join on id
我正在使用 Mapstruct 将生成的 DTO(地铁,xsd)映射到我们的业务领域对象。我的困难是 DTO 实际上并不引用子对象,而是使用 ID 来引用关联的实例。
为了将其分解为一个简化的案例,我想出了一个例子:
SchoolDTO 有一个教师和课程列表。一个老师
每门课程仅通过 teacherId
引用课程。
在业务领域学校只有一个教师列表
持有他们的课程列表。
Class 图:UML: DTO / Domain
最初我希望在 mapstruct 语法中解决这个问题,例如在 foreignId 和教师 id(或一些 qualifiedBy 关联)上的连接,伪代码如下:
@Mapping(source="courses", target="teachers.courses", where="teacher.id = course.teacherId")
DTO:
public class SchoolDto {
List<TeacherDto> teachers;
List<CourseDto> courses;
}
public class TeacherDto {
String id;
String name;
}
public class CourseDto {
String name;
String teacherId;
}
域:
public class School {
List<Teacher> teachers;
}
public class Teacher {
String name;
List<Course> courses;
}
public class Course {
String name;
}
我现在正在使用相当大的 @AfterMapping
方法解决它,但我觉得这不是一个特殊的用例 - 所以也许我遗漏了一些相当明显的东西。什么是 correct/intended 方式 来解决这些类型的 "joins" 在 Mapstruct 的映射中?
我怀疑你是否可以在没有 @AfterMapping
的情况下做到这一点。 MapStruct "just" 用于将一个对象映射到另一个对象,它不支持任何类型的查找或连接数据的查询。
如果您还没有使用它,这听起来像是一个使用上下文的好用例。那么@AfterMapping
其实并不大:
@Mapper
public abstract class SchoolMapper {
public School toSchool(SchoolDto school) {
return toSchool( school, school.getCourses() );
}
protected abstract School toSchool(SchoolDto school, @Context List<CourseDto> courses);
@Mapping(target = "courses", ignore = true) // see afterMappingToTeacher
protected abstract Teacher toTeacher(TeacherDto teacher, @Context List<CourseDto> courses);
protected abstract Course toCourse(CourseDto course);
@AfterMapping
void afterMappingToTeacher(@MappingTarget target, TeacherDto source, @Context List<CourseDto> courses) {
// omitted null-checks
List<Course> courses = new ArrayList<>();
for(CourseDto course : courses) {
if(course.getTeacherId().equals(source.getId())) {
courses.add( toCourse(course) );
}
}
target.setCourses( courses );
}
}
(当使用 Java >= 8 你可以使用默认方法的接口)
如果您需要多次查询事物,您可以创建自己的 class 作为上下文,例如,它有自己的方法来通过教师 ID 查找所有课程。
我正在使用 Mapstruct 将生成的 DTO(地铁,xsd)映射到我们的业务领域对象。我的困难是 DTO 实际上并不引用子对象,而是使用 ID 来引用关联的实例。
为了将其分解为一个简化的案例,我想出了一个例子:
SchoolDTO 有一个教师和课程列表。一个老师 每门课程仅通过
teacherId
引用课程。在业务领域学校只有一个教师列表 持有他们的课程列表。
Class 图:UML: DTO / Domain
最初我希望在 mapstruct 语法中解决这个问题,例如在 foreignId 和教师 id(或一些 qualifiedBy 关联)上的连接,伪代码如下:
@Mapping(source="courses", target="teachers.courses", where="teacher.id = course.teacherId")
DTO:
public class SchoolDto {
List<TeacherDto> teachers;
List<CourseDto> courses;
}
public class TeacherDto {
String id;
String name;
}
public class CourseDto {
String name;
String teacherId;
}
域:
public class School {
List<Teacher> teachers;
}
public class Teacher {
String name;
List<Course> courses;
}
public class Course {
String name;
}
我现在正在使用相当大的 @AfterMapping
方法解决它,但我觉得这不是一个特殊的用例 - 所以也许我遗漏了一些相当明显的东西。什么是 correct/intended 方式 来解决这些类型的 "joins" 在 Mapstruct 的映射中?
我怀疑你是否可以在没有 @AfterMapping
的情况下做到这一点。 MapStruct "just" 用于将一个对象映射到另一个对象,它不支持任何类型的查找或连接数据的查询。
如果您还没有使用它,这听起来像是一个使用上下文的好用例。那么@AfterMapping
其实并不大:
@Mapper
public abstract class SchoolMapper {
public School toSchool(SchoolDto school) {
return toSchool( school, school.getCourses() );
}
protected abstract School toSchool(SchoolDto school, @Context List<CourseDto> courses);
@Mapping(target = "courses", ignore = true) // see afterMappingToTeacher
protected abstract Teacher toTeacher(TeacherDto teacher, @Context List<CourseDto> courses);
protected abstract Course toCourse(CourseDto course);
@AfterMapping
void afterMappingToTeacher(@MappingTarget target, TeacherDto source, @Context List<CourseDto> courses) {
// omitted null-checks
List<Course> courses = new ArrayList<>();
for(CourseDto course : courses) {
if(course.getTeacherId().equals(source.getId())) {
courses.add( toCourse(course) );
}
}
target.setCourses( courses );
}
}
(当使用 Java >= 8 你可以使用默认方法的接口)
如果您需要多次查询事物,您可以创建自己的 class 作为上下文,例如,它有自己的方法来通过教师 ID 查找所有课程。