I have entity called Franchise and this entity looks like this:
@Data
@Entity
@Table(name = "franchises")
public class Franchise {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@Enumerated(EnumType.STRING)
private FranchiseType type;
@ToString.Exclude
@EqualsAndHashCode.Exclude
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "country_id")
private Country country;
}
I have following api endpoint for creating new Franchise entity: POST /api/franchise
And fields that I need to send are: name
, type
and countryId
. countryId
is optional field and can be null in the database (column country_id
).
I am using mapstruct to map CreateFranchiseDTO
to Franchise
:
@Data
public class CreateFranchiseDTO {
private String name;
private String type;
private Long countryId;
}
@Mapper(componentModel = "spring")
public interface FranchiseDTOMapper {
@Mapping(source = "countryId", target = "country.id")
Franchise fromCreateFranchiseDTO(CreateFranchiseDTO dto);
}
When I call above mentioned api endpoint with countryId
set to some integer (which exists in countries
table) everythng works. But if I call endpoint without countryId
field in request body and when the following code executes I get exception object references an unsaved transient instance
:
Franchise franchise = franchiseDTOMapper.fromCreateFranchiseDTO(dto);
franchiseRepository.save(franchise);
When I look at the debugger I can see that franchise.getCountry()
is equal to Country
object with all fields set to NULL or zero/false (default values for primitives)
I have few options to solve this:
- using
@AfterMapping
and check forfranchise.getCountry().getId() == null
- create following method in mapper:
Country longToCountry(Long id)
But it seems to me that I am missing something or I am wrong. So how do I map an optional ID (relation) to field using mapstruct?