okay, i have an 3 entities: Topic, User, Category, Picture. 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
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.
I trying to write a CRUD services for each entities, into which i inject repositories that extends 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? Sorry for my awful english
CodePudding user response:
You can create an of
method within your TopicDTO
class to construct the object. Providing the userDTO and categoryDTO as arguements will allow them to be set to null or their respective objects if they exist.
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);
}
}
CodePudding user response:
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. (For example it's testable only with junit4).
You should rather use Lombok builders to instantiate DTOs from your entities. Futhermore you can test it easily with junit5 in TDD like this :
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();
}
}
CodePudding user response:
In simple words, to convert Entity to DTO you have to use the ModelMapper library.
1.Add ModelMapper dependency in your Spring or Spring Boot application.
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>2.4.4</version>
Define the Model Mapper bean in our Spring configuration file. This step is required to inject the beans.
@Bean public ModelMapper modelMapper() { return new ModelMapper(); }
Inject and use the ModelMapper in your class where you want to convert the entity to Dto.
@Autowired private ModelMapper modelMapper;
Input as Employee Entity to Dto Conversion
{ "id" : 1, "name" : "Robert", "designation" : "Product Engineer", "age" : 25, "experience" : "5", "isEngneeringEmployee" : true }
Output as Employee Dto
{ "employeeId": 1, "name": "Robert", "designation": "Product Engineer", "experience": 5 }
example so that we can understand it in a better way.
private EmployeeDto entityToDtoConversion(Employee employee){ return modelMapper.map(employee, EmployeeDto.class); }
for more info please refer this article.
https://codezup.com/convert-entity-to-dto-in-spring-and-spring-boot-example/