I couldn't find the answer to my question, I hope this is not a duplicate question. Below is illustrated made-up example.
data table "user":
+--+--------+
|id|username|
+--+--------+
|1 |someUser|
+--+--------+
I would like to know what is the difference when:
- Entity (contact) is saved to the database in a way where 'userId' is mapped as a foreign key value (eg. 1)
- Entity (contact) saved is to the database in a way where 'userId' is used to retrieve the respective User entity from the database and set to contact.
Controller
@RestController
public class ContactController {
// to keep is short, all action is here in controller
@Resource
private ContactMapper contactMapper;
@Resource
private ContactRepository contactRepository;
@Resource
private UserRepository userRepository;
@PostMapping("/as-foreign-key")
public void addContactWithUserIdForeignKey(@RequestBody ContactDto dto) {
Contact contact = contactMapper.contactDtoToContact(dto);
contactRepository.save(contact);
}
@PostMapping("/as-entity")
public void addContactWithUserEntity(@RequestBody ContactDto dto) {
User user = userRepository.findById(dto.getUserId()).get();
Contact contact = contactMapper.contactDtoToContact(dto);
contact.setUser(user);
contactRepository.save(contact);
}
}
DTO
@Data
public class ContactDto implements Serializable {
private final String firstName;
private final String lastName;
private final Integer userId;
}
MapStruct mapper
@Mapper(unmappedTargetPolicy = ReportingPolicy.IGNORE, componentModel = "spring")
public interface ContactMapper {
@Mapping(source = "userId", target = "user.id")
Contact contactDtoToContact(ContactDto contactDto);
}
Entities
@Data
@Entity
@Table(name = "\"user\"")
public class User {
@Id
@Column(name = "id", nullable = false)
private Integer id;
@Column(name = "username", nullable = false, length = 50)
private String username;
}
@Data
@Entity
@Table(name = "contact")
public class Contact {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private Integer id;
@Column(name = "first_name", nullable = false, length = 50)
private String firstName;
@Column(name = "last_name", nullable = false, length = 50)
private String lastName;
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "user_id", nullable = false)
private User user;
}
Executing both requests:
curl -X 'POST' \
'http://localhost:8080/as-foreign-key' \
-H 'accept: */*' \
-H 'Content-Type: application/json' \
-d '{
"firstName": "John",
"lastName": "Doe",
"userId": 1
}'
curl -X 'POST' \
'http://localhost:8080/as-entity' \
-H 'accept: */*' \
-H 'Content-Type: application/json' \
-d '{
"firstName": "Jane",
"lastName": "Done",
"userId": 1
}
Result
data table "contact":
+--+----------+---------+-------+
|id|first_name|last_name|user_id|
+--+----------+---------+-------+
|1 |John |Doe |1 |
|2 |Jane |Done |1 |
+--+----------+---------+-------+
Both ways produce the same result.
Looking from console, I can see the following hibernate SQL statements.
Hibernate: select user_.id, user_.username as username2_1_ from "user" user_ where user_.id=?
Hibernate: insert into contact (first_name, last_name, user_id) values (?, ?, ?)
Hibernate: select user0_.id as id1_1_0_, user0_.username as username2_1_0_ from "user" user0_ where user0_.id=?
Hibernate: insert into contact (first_name, last_name, user_id) values (?, ?, ?)
So far I have always thought that the correct way is the second way: first, find the Entity (user), use setter, and then save.
Is there any technical difference between these two approaches? Could I safely go via the first way or is there something that I should consider?
Any info around this subject is much appreciated.
