0

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:

  1. using @AfterMapping and check for franchise.getCountry().getId() == null
  2. 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?

clzola
  • 1,925
  • 3
  • 30
  • 49

1 Answers1

0

If I understand correctly, you have the same problem as this person.

What seems to have worked for that person was to use optional = true:

@ManyToOne(optional = true, fetch = FetchType.LAZY)
HoolaBoola
  • 65
  • 5
  • `optional = true` is default value – clzola Jul 03 '20 at 18:34
  • Ah, you're right. Seems I didn't do my research properly before answering. For anyone curious, [here](https://docs.oracle.com/javaee/7/api/javax/persistence/ManyToOne.html) is some documentation – HoolaBoola Jul 03 '20 at 18:45