由另一个映射器映射的内部字段发生 Mapstruck null 故障

问题描述 投票:0回答:1

在我的应用程序中,每个聊天都包含一个消息列表,每个消息都包含有关作为其发送者和接收者的用户的信息。但是,我正在努力使用带有 mapstruct 的映射器,聊天映射器将允许我映射消息列表和与每条消息相关的用户信息,这些信息由消息映射器映射。

因此,此操作失败并显示有效消息,但 userTo 和 userFrom id 为空。

return chatRepository.findAll()
        .stream()
        .map(chatMapper::toModel)
        .toList();

但是当它被下面的部分替换时,我映射每条消息,然后手动将它们添加到聊天中,它就会通过:

List<ChatEntity> chatEntityList = chatRepository.findAll();

List<Chat> chatList = new ArrayList<>();
for (ChatEntity chatEntity : chatEntityList) {
    List<Message> messageList = chatEntity.getMessageEntityList()
            .stream()
            .map(messageMapper::toModel)
            .toList();

    Chat chat = Chat.builder()
            .id(chatEntity.getId())
            .messageList(messageList)
            .build();

    chatList.add(chat);
}
return chatList;

我已经尝试了好几天了,但真的不知道这是为什么?

这些是我的地图绘制者:

@Mapper //tried @Mapper(uses = MessageMapper.class) but the result is the same
public interface ChatMapper {

    @Mapping(source = "messageList", target = "messageEntityList")
    ChatEntity toEntity(Chat chat);

    @Mapping(source = "messageEntityList", target = "messageList")
    Chat toModel(ChatEntity chatEntity);
}

@Mapper
public interface MessageMapper {

    @Mapping(source = "userFromId", target = "userFromEntity.id")
    @Mapping(source = "userToId", target = "userToEntity.id")
    MessageEntity toEntity(Message message);

    @Mapping(source = "userFromEntity.id", target = "userFromId")
    @Mapping(source = "userToEntity.id", target = "userToId")
    Message toModel(MessageEntity messageEntity);
}

这里的模型:

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Chat {

    private UUID id;

    @JsonProperty("messages")
    private List<Message> messageList;
}

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Message {

    private UUID id;
    private String content;
    private ZonedDateTime creationDate;
    private UUID parentId;
    private UUID userFromId;
    private UUID userToId;
}

和实体:

@Entity
@Table(name = "chat")
@Builder(toBuilder = true)
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class ChatEntity {
    @Id
    @Column(name = "id")
    private UUID id;

    @OneToMany(mappedBy = "chatEntity", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    private List<MessageEntity> messageEntityList;
}

@Entity
@Table(name = "message")
@Builder(toBuilder = true)
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class MessageEntity {

    @Id
    @GeneratedValue
    @Column(name = "id")
    private UUID id;

    @Column(name = "content")
    private String content;

    @Column(name = "creation_date")
    private ZonedDateTime creationDate;

    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
    @JoinColumn(name = "user_to_id", referencedColumnName = "id")
    private UserEntity userToEntity;

    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
    @JoinColumn(name = "user_from_id", referencedColumnName = "id")
    private UserEntity userFromEntity;

    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
    @JoinColumn(name = "chat_id", referencedColumnName = "id")
    private ChatEntity chatEntity;
}
java spring mapping mapstruct
1个回答
0
投票

我知道您提到您获得了相同的结果,但在我看来,使用以下

Mapper
定义应该会给您正确的结果:

@Mapper(uses = MessageMapper.class)
public interface ChatMapper {

    @Mapping(source = "messageList", target = "messageEntityList")
    ChatEntity toEntity(Chat chat);

    @Mapping(source = "messageEntityList", target = "messageList")
    Chat toModel(ChatEntity chatEntity);
}

如果此代码不起作用,请注意您的 JPA 关系:所有关系都定义为惰性关系,并且可能在评估映射器时尚未初始化它们。

请分析生成的映射器的源代码,它将让您更好地理解它正在执行的实际代码。

作为解决方法,请考虑将发送和接收消息的用户的标识符作为附加只读列包含在您的

MessageEntity
:

@Entity
@Table(name = "message")
@Builder(toBuilder = true)
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class MessageEntity {

    @Id
    @GeneratedValue
    @Column(name = "id")
    private UUID id;

    @Column(name = "content")
    private String content;

    @Column(name = "creation_date")
    private ZonedDateTime creationDate;

    @Column(name = "user_to_id", updatable=false, insertable=false)
    private UUID userToEntityId;

    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
    @JoinColumn(name = "user_to_id", referencedColumnName = "id")
    private UserEntity userToEntity;

    @Column(name = "user_from_id", updatable=false, insertable=false)
    private UUID userFromEntityId;

    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
    @JoinColumn(name = "user_from_id", referencedColumnName = "id")
    private UserEntity userFromEntity;

    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
    @JoinColumn(name = "chat_id", referencedColumnName = "id")
    private ChatEntity chatEntity;

并修改

MessageMapper
以考虑新列:

@Mapper
public interface MessageMapper {

    @Mapping(source = "userFromId", target = "userFromEntityId")
    @Mapping(source = "userToId", target = "userToEntityId")
    MessageEntity toEntity(Message message);

    @Mapping(source = "userFromEntityId", target = "userFromId")
    @Mapping(source = "userToEntityId", target = "userToId")
    Message toModel(MessageEntity messageEntity);
}

如果您采用这种新方法,请注意关系的解决方式。

© www.soinside.com 2019 - 2024. All rights reserved.