Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Spring Boot Single table inheritance-could not execute statement; SQL [n/a]; constraint [phone_number" of relation "contact_information]]

When I try save entity, I faced this error. My request;

{
  "contactInformationType": "EMAIL",
  "candidateId": 1,
  "emailAddress": "asa@gmail.com"
}

I think the problem is because it doesn’t take the phone_number variable when registering in email type.
My dtos’ content:

@Data
public class ContactInformationSaveRequestDto {
    private final ContactInformationType contactInformationType;
    private final Long candidateId;
    @Nullable
    private final String phoneNumber;
    @Nullable
    private final String emailAddress;
}
@EqualsAndHashCode(callSuper = true)
@Data
@SuperBuilder
public class EmailContactInformationDto extends ContactInformationDto {
    private String emailAddress;
}
@EqualsAndHashCode(callSuper = true)
@Data
@SuperBuilder
public class PhoneNumberContactInformationDto extends ContactInformationDto{
    private String phoneNumber;
}

Entities:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

@Entity
@Getter
@Setter
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "contact_information_type", length = 30, discriminatorType = DiscriminatorType.STRING)
public abstract class ContactInformation extends BaseEntity {
    @Id
    @SequenceGenerator(name = "contactInfoSeq", sequenceName = "contact_info_id_sec")
    @GeneratedValue(generator="contactInfoSeq")
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "candidate_id", nullable = false)
    private Candidate candidate;

}
@Entity
@DiscriminatorValue(value="EMAIL")
@Getter
@Setter
public class EmailContactInformation extends ContactInformation {
   @Column(name = "email_address", nullable = false)
    private String emailAddress;
}
@Entity
@DiscriminatorValue(value="PHONE_NUMBER")
@Getter
@Setter
public class PhoneNumberContactInformation extends ContactInformation {
   @Column(name = "phone_number", nullable = false)
    private String phoneNumber;
}

Mappers:

@Mapper
public interface ContactInformationMapper {
    ContactInformationMapper INSTANCE = Mappers.getMapper(ContactInformationMapper.class);

    default ContactInformation map(ContactInformationSaveRequestDto dto) {
        ContactInformation entity = null;
        switch(dto.getContactInformationType()) {
            case EMAIL:
                entity = EmailContactInformationMapper.INSTANCE.contactInformationSaveRequestDtoToContactInformation(dto);
                break;
            case PHONE_NUMBER:
                entity = PhoneNumberContactInformationMapper.INSTANCE.contactInformationSaveRequestDtoToContactInformation(dto);
                break;
        }
        return entity;
    }

    @Named("contactInformationSetMapping")
    default Set<ContactInformation> contactInformationSetMapping(Set<ContactInformationSaveRequestDto> dtos) {
        if (dtos == null) {
            return Collections.emptySet();
        }

        return dtos.stream()
                .map(this::map)
                .collect(Collectors.toSet());
    }

}
@Mapper(unmappedTargetPolicy = ReportingPolicy.IGNORE, componentModel = "spring")
public interface EmailContactInformationMapper {
    EmailContactInformationMapper INSTANCE = Mappers.getMapper(EmailContactInformationMapper.class);
    EmailContactInformation contactInformationSaveRequestDtoToContactInformation(ContactInformationSaveRequestDto contactInformationSaveRequestDto);

    ContactInformationDto contactInformationToContactInformationDto(ContactInformation savedContactInformation);


}
@Mapper(unmappedTargetPolicy = ReportingPolicy.IGNORE, componentModel = "spring")

public interface PhoneNumberContactInformationMapper {
    PhoneNumberContactInformationMapper INSTANCE = Mappers.getMapper(PhoneNumberContactInformationMapper.class);
    PhoneNumberContactInformation contactInformationSaveRequestDtoToContactInformation(ContactInformationSaveRequestDto contactInformationSaveRequestDto);

    ContactInformationDto contactInformationToContactInformationDto(ContactInformation savedContactInformation);
}

Repositories:

@NoRepositoryBean
public interface ContactInformationRepository<T extends ContactInformation> extends JpaRepository<T, Long> {
}
@Repository
public interface EmailContactInformationRepository extends ContactInformationRepository<EmailContactInformation>{
}

On Service Layer:

@Service
public class ContactInformationServiceImpl
    @Override
    public ContactInformationDto saveContactInformation(ContactInformationSaveRequestDto contactInformationSaveRequestDto) {
        ContactInformation savedContactInformation;
        Candidate candidate=candidateService.getCandidateById(contactInformationSaveRequestDto.getCandidateId());
        if (candidate==null) {
            throw new IllegalArgumentException("Candidate not found");
        }
        if (contactInformationSaveRequestDto.getContactInformationType().equals(ContactInformationType.EMAIL)) {
            EmailContactInformation emailContactInformation=EmailContactInformationMapper.INSTANCE.contactInformationSaveRequestDtoToContactInformation(contactInformationSaveRequestDto);
            emailContactInformation.setCandidate(candidate);
            savedContactInformation=emailContactInformationRepository.save(emailContactInformation);
            return null;
        } else if (contactInformationSaveRequestDto.getContactInformationType().equals(ContactInformationType.PHONE_NUMBER)) {
            savedContactInformation=phoneNumberContactInformationRepository.
                    save(PhoneNumberContactInformationMapper.INSTANCE.contactInformationSaveRequestDtoToContactInformation(contactInformationSaveRequestDto));
            return PhoneNumberContactInformationMapper.INSTANCE.contactInformationToContactInformationDto(savedContactInformation);
        }
        throw new GeneralBusinessException(GeneralErrorMessage.CONTACT_INFORMATION_TYPE_NOT_FOUND);
    }

The method takes a ContactInformationSaveRequestDto as a parameter. It tries to find the candidate by the candidateId in the ContactInformationSaveRequestDto.

If the candidate is not found, an IllegalArgumentException is thrown. If the contactInformationType in the ContactInformationSaveRequestDto is EMAIL, the EmailContactInformationMapper is used to map the ContactInformationSaveRequestDto to a ContactInformation object.

The candidate is set in the ContactInformation object. The EmailContactInformationRepository is used to save the ContactInformation object.

The save() method returns the saved ContactInformation object. The method returns null in the end.

If the contactInformationType in the ContactInformationSaveRequestDto is PHONE_NUMBER, the PhoneNumberContactInformationMapper is used to map the ContactInformationSaveRequestDto to a ContactInformation object. The candidate is set in the ContactInformation object. The PhoneNumberContactInformationRepository is used to save the ContactInformation object.

The save() method returns the saved ContactInformation object. The PhoneNumberContactInformationMapper is used to map the ContactInformation to a ContactInformationDto. The method returns the mapped ContactInformationDto in the end.

If the contactInformationType in the ContactInformationSaveRequestDto is neither EMAIL nor PHONE_NUMBER, a

>Solution :

You define:

@Data
public class ContactInformationSaveRequestDto {
    private final ContactInformationType contactInformationType;
    private final Long candidateId;
    @Nullable
    private final String phoneNumber;
    @Nullable
    private final String emailAddress;
}

That means that phoneNumber is required but can be null:

@Nullable
private final String phoneNumber;

And phoneNumber is redefined/once again defined in (THIS HAS TO BE FIXED):

@EqualsAndHashCode(callSuper = true)
@Data
@SuperBuilder
public class PhoneNumberContactInformationDto extends ContactInformationDto{
    private String phoneNumber;
}

Unless you explicitly want exclude changing phoneNumber and emailAddress at the same time, you have to reconsider your DTOs to allow for "optional" changes.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading