简体   繁体   English

如何将实体转换为 dto,反之亦然?

[英]How to convert entity to dto, and vice versa?

okay, i have an 3 entities: Topic, User, Category, Picture.好的,我有 3 个实体:主题、用户、类别、图片。 User have a picture, and topic have an User and Category.用户有图片,主题有用户和类别。

class Topic {

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

    @Column(nullable = false)
    String header;

    @Column(nullable = false)
    String description;

    @Column(name = "is_anonymous", nullable = false)
    boolean isAnonymous;

    @DateTimeFormat(pattern = "yyyy-MM-dd hh:mm:ss")
    @Column(name = "creation_date", nullable = false)
    LocalDateTime creationDate;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "author_id", nullable = false)
    User author;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "category_id", nullable = false)
    Category category;
}

And i also have an topic DTO我还有一个主题 DTO

class TopicDTO {

    String header;

    String description;

    boolean isAnonymous;

    LocalDateTime creationDate;

    UserDTO userDTO;

    CategoryDTO categoryDTO;
}

I can to inject ModelMapper into TopicService, and use it to convert, but it doesn't work as I need, in this case, if i trying to convert Topic to TopicDTO, in the converted TopicDTO object, UserDTO and CategoryDTO will be null, but in the debug, before converting, in the Topic object - Category object and User object is not null, they are initialized.我可以将 ModelMapper 注入到 TopicService 中,并使用它进行转换,但它不能按我的需要工作,在这种情况下,如果我尝试将 Topic 转换为 TopicDTO,在转换后的 TopicDTO object 中,UserDTO 和 CategoryDTO 将是 null,但是在调试中,在转换之前,在主题 object - 类别 object 和用户 object 中未初始化 Z37A6259CC0C1DAE2911C4B666Z,它们是

I trying to write a CRUD services for each entities, into which i inject repositories that extends CrudRepository.我试图为每个实体编写一个 CRUD 服务,我将扩展 CrudRepository 的存储库注入其中。 And when i get from controller TopicDTO, i call topicService.save(topicDTO), but in the topic service, method save, i dont want to cascade save user, i dont want to cascade save categories, i want to save topic with existing samples category and user, how i can to do that?当我从 controller TopicDTO 获取时,我调用 topicService.save(topicDTO),但在主题服务中,方法保存,我不想级联保存用户,我不想级联保存类别,我想用现有样本保存主题类别和用户,我该怎么做? Sorry for my awful english对不起我糟糕的英语

You can create an of method within your TopicDTO class to construct the object.您可以在TopicDTO class 中创建一个of方法来构造 object。 Providing the userDTO and categoryDTO as arguements will allow them to be set to null or their respective objects if they exist.提供 userDTO 和 categoryDTO 作为参数将允许将它们设置为 null 或它们各自的对象(如果存在)。

class TopicDTO {

    String header;

    String description;

    //all the other variables...

    public static TopicDTO of(Topic topic, UserDTO userDTO, CategoryDTO categoryDTO) {
    return new TopicDTO(
            topic.getHeader(),
            topic.getDescription(),
            topic.getIsAnonymous(),
            topic.getCreationDate(),
            userDTO,
            categoryDTO);
    }
}

You can either use a code generator like MapStruct which I really don't preconise as you'll have to learn how to annotate your DTOs in order to map them and that it's quite deprecated.您可以使用像 MapStruct 这样的代码生成器,因为您必须学习如何注释您的 DTO 才能对它们进行 map 并且它已被弃用。 (For example it's testable only with junit4). (例如,它只能使用 junit4 进行测试)。

You should rather use Lombok builders to instantiate DTOs from your entities.您应该使用 Lombok 构建器从您的实体实例化 DTO。 Futhermore you can test it easily with junit5 in TDD like this:此外,您可以像这样在 TDD 中使用 junit5 轻松测试它:

class TopicMapperTest {

    TopicMapper topicMapper;

    @Mock
    UserMapper userMapper;

    Clock clock;

    @BeforeEach
    void setUp() {
        topicMapper = new TopicMapper();
        clock = Clock.fixed(LocalDateTime.now().toInstant());
    }

    @Test
    void should_map_topic_to_topicDTO() {
        // Given
        Topic topic = new Topic(1, "header", "description", false, LocalDateTime.now(clock), new User(), new Category());

        TopicDTO expected = TopicDTO.builder()
                .header("header")
                .description("description")
                .isAnonymous(false)
                .creationDate(LocalDateTime.of())
                .userDTO(userMapper.mapUser(new User()))
                .categoryDTO(categoryMapper.mapCategory(new Category()))
                .build();


        // When
        TopicDTO result = topicMapper.mapTopic(topic);

        // Then
        assertEquals(expected, result);
    }
}

And your mapper should looks like (I let you complete it to make your test pass):你的映射器应该看起来像(我让你完成它以使你的测试通过):

public class TopicMapper {

    UserMapper userMapper = new UserMapper();

    public TopicDTO mapTopic(Topic topic) {
        return TopicDTO.builder()
                .header(topic.getHeader())
                .description(topic.getDescription())
                .userDTO(userMapper.mapUser(topic.getAuthor()))
                .isAnonymous(topic.isAnonymous())
                .build();
    }
}

Влад, you should use constructors to create objects only. Влад,您应该只使用构造函数来创建对象。 Do not use getters/setters when instantiating the object because this is anti pattern.在实例化 object 时不要使用 getter/setter,因为这是反模式。 It's hard to maintain what setter you have used already and what not.很难维护您已经使用过的 setter 和未使用过的 setter。 Object should be fully created through constructor and key word 'new' and it will have state immediately. Object 应通过构造函数和关键字“new”完全创建,它将立即具有 state。

To map Entity to dto I would suggest create simple Mapper class that accept Entity in constructor and return new dto object and that's it.到 map 实体到 dto 我建议创建简单的映射器 class 接受构造函数中的实体并返回新的 dto object 就是这样。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM