Why doesn't Mybatis map a simple ENUM correctly? - spring-boot

I'm not doing anything out of the ordinary from what I can tell. I have a spring boot application using mybatis:
implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.1.1'
I have an application.properties config for mybatis that is pretty simple:
## MyBatis ##
mybatis.configuration.map-underscore-to-camel-case=true
mybatis.configuration.default-statement-timeout=30
My database table looks like this:
CREATE TABLE workspace_external_references (
id CHAR(36) PRIMARY KEY,
workspace_id CHAR(36) NOT NULL,
site VARCHAR(255) NOT NULL,
external_id VARCHAR(255) NOT NULL,
created_at DATETIME(6) NOT NULL DEFAULT NOW(6),
updated_at DATETIME(6) NOT NULL DEFAULT NOW(6),
FOREIGN KEY (workspace_id) REFERENCES workspaces (id) ON DELETE CASCADE
)
With just a single entry like this:
'a907c0af-216a-41e0-b16d-42107a7af05f', 'e99e4ab4-839e-405a-982b-08e00fbfb2d4', 'ABC', '6', '2020-06-09 00:19:20.135822', '2020-06-09 00:19:20.135822'
In my mapper file I'm doing a select of all references like this:
#Select("SELECT * FROM workspace_external_references WHERE workspace_id = #{workspaceId}")
List<WorkspaceExternalReference> findByWorkspace(#Param("workspaceId") final UUID workspaceId);
And the java object that this is supposed to map to looks like this:
public class WorkspaceExternalReference {
private UUID id;
private UUID workspaceId;
private Sites site;
private String externalId;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
public WorkspaceExternalReference(
final Sites site,
final UUID workspaceId,
final String externalId) {
this.site = site;
this.workspaceId = workspaceId;
this.externalId = externalId;
}
}
public enum Sites {
ABC, XYZ;
}
Sooooo why doesn't this work? I get this error back:
Caused by: org.apache.ibatis.executor.result.ResultMapException: Error attempting to get column 'id' from result set. Cause: java.lang.IllegalArgumentException: No enum constant com.acme.Sites.a907c0af-216a-41e0-b16d-42107a7af05f

When there is no default constructor, you need to let MyBatis know which columns to pass to the constructor explicitly (in most cases).
With annotations, it would look as follows.
You can use <resultMap> and <constructor> in XML mapper.
#ConstructorArgs({
#Arg(column = "site", javaType = Sites.class),
#Arg(column = "workspace_id", javaType = UUID.class),
#Arg(column = "external_id", javaType = String.class)
})
#Select("SELECT * FROM workspace_external_references WHERE workspace_id = #{workspaceId}")
List<WorkspaceExternalReference> findByWorkspace(#Param("workspaceId") final UUID workspaceId);
Other columns (i.e. id, created_at, updated_at) will be auto-mapped via setters (if there are) or reflection.
Alternatively, you can just add the default (no-arg) constructor to the WorkspaceExternalReference class. Then all columns will be auto-mapped after the class is instantiated.
Note: To make it work, there needs to be a type handler registered for UUID, but you seem to have done it already (otherwise the parameter mapping wouldn't work).

Related

Error while testing with H2 database with Reactive Spring boot

I am using Reactive Spring boot to create a REST API and while the API works perfectly (I have tested it with postman), I also need to write some Unit tests and for the Unit tests I need to use a seperate in-memory database for it. I am using H2 database for testing and a hosted Postgres DB for the actual application and while my application entities are being loaded successfully in the postgres DB, None of my tests are passing as I receieve the following error:
Failed to execute SQL script statement #1 of class path resource [data.sql]: CREATE TABLE IF NOT EXISTS full_connection ( id BIGINT PRIMARY KEY , aa TEXT NOT NULL, fip TEXT NOT NULL, status TEXT, created_on TIMESTAMP, created_by TEXT, last_updated_on TIMESTAMP, last_updated_by TEXT ); nested exception is java.lang.ClassCastException: class java.lang.Long cannot be cast to class java.lang.Integer (java.lang.Long and java.lang.Integer are in module java.base of loader 'bootstrap')
I am assuming the error is being thrown because of the id paramater which has the datatype BIGINT which the official documentation of H2 says is mapped to java.long.Long.
Here's my entity:
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Builder
#ToString
#Table
public class FullConnection {
#Id
#Column(name = "id")
private Long id;
#Column(name = "AA", nullable = false)
private String aa;
#Column(name = "FIP", nullable = false)
private String fip;
private String status;
private LocalDateTime createdOn;
private String createdBy;
private LocalDateTime lastUpdatedOn;
private String lastUpdatedBy;
}
Here's how I am initializing the data:
#Bean
ConnectionFactoryInitializer initializer(#Qualifier("connectionFactory") ConnectionFactory connectionFactory) {
ConnectionFactoryInitializer initializer = new ConnectionFactoryInitializer();
initializer.setConnectionFactory(connectionFactory);
ResourceDatabasePopulator resource =
new ResourceDatabasePopulator(new ClassPathResource(dataInitializerName));
initializer.setDatabasePopulator(resource);
return initializer;
}
where it's reading the dataInitializerName string from application-test.yaml and is being read correctly, the script (for testing)(the script for prod and testing are different) is:
CREATE TABLE IF NOT EXISTS full_connection (
id BIGINT PRIMARY KEY ,
aa TEXT NOT NULL,
fip TEXT NOT NULL,
status TEXT,
created_on TIMESTAMP,
created_by TEXT,
last_updated_on TIMESTAMP,
last_updated_by TEXT
);
Here: https://www.h2database.com/html/datatypes.html#bigint_type it clearly states that BIGINT is mapped to java.long.Long, then why is it trying to cast it to int? Or is it regarding some other field?
I had a similar problem. Explicitly defining the version for the dependency r2dbc-h2 in pom.xml is causing the problem. I removed the version so that springboot will automatically use the compatible version of r2dbc-h2, and then the problem resolved.

Unknown Column Error while attempting a many-to-one entity mapping

I followed this example, renaming Student to Journey, and renaming Library to Station. My interpretation of the error is, the table schema does not have a field called 'departure' while the java class representation does. I didn't expect this to be a problem because I followed the JPA naming convention mentioned in this answer. In the example's case, lib + b_id == LIB_B_ID . In my case, departure + station_id == departure_station_id (my database naming scheme uses lowercase).
Other notable differences to the example, I don't have a persistence.xml, for id I use GenerationType.IDENTITY not GenerationType.AUTO .
Error
java.sql.SQLException: Unknown column 'departure' in 'field list'
Schema script
CREATE TABLE `station` (
`station_id` bigint(20) NOT NULL AUTO_INCREMENT,
`locker_id` bigint(20) DEFAULT NULL,
`station_name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`station_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2579 DEFAULT CHARSET=utf8
CREATE TABLE `journey` (
`journey_id` bigint(20) NOT NULL AUTO_INCREMENT,
`departure_station_id` bigint(20) DEFAULT NULL,
`destination_station_id` bigint(20) DEFAULT NULL,
PRIMARY KEY (`journey_id`),
KEY `station_id_departure` (`departure_station_id`),
KEY `station_id_destination` (`destination_station_id`),
CONSTRAINT `journey_ibfk_1` FOREIGN KEY (`destination_station_id`) REFERENCES `station` (`station_id`),
CONSTRAINT `journey_ibfk_2` FOREIGN KEY (`departure_station_id`) REFERENCES `station` (`station_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
Journey
#Entity
public class Journey implements Serializable{//Serializable required by #JoinColumn
//Station
public Journey(Station departure, Station destination){
this.departure = departure;
this.destination = destination;
}
//List<Station>
public Journey(List<Station> journeyStationList){
departure = journeyStationList.get(0);//0 is first index
destination = journeyStationList.get(journeyStationList.size() - 1);//-1 because first index of List is 0
}
private Long journeyId;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public Long getJourneyId(){
return journeyId;
}
public void setJourneyId(Long journeyId){
this.journeyId = journeyId;
}
#ManyToOne
private Station departure;
public Station getDeparture(){
return departure;
}
public void setDeparture(Station departure){
this.departure = departure;
}
#ManyToOne
private Station destination;
public Station getDestination(){
return destination;
}
public void setDestination(Station destination){
this.destination = destination;
}
}
Station
#Entity
public class Station implements Serializable{//Serializable required by #JoinColumn
public Station(){//default constructor needed for JPA query
}
public Station(String stationName){
setStationName(stationName);
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long stationId;
public Long getStationId(){
return stationId;
}
public void setStationId(Long stationId){
this.stationId = stationId;
}
private String stationName;
public String getStationName(){
return stationName;
}
public void setStationName(String stationName){
this.stationName = stationName;
}
}
In contrast to the two examples I cross referenced A and B, I noticed in this question the #ManyToOne annotation was above the getter not the field's declaration. Because my currently working annotations (#id and #GeneratedValue) was also above a getter it seemed like a plausible solution. After moving the annotation to the getter, the error went away.
The examples were not wrong, they were just using a different access strategy than what I had inadvertently implicitly set by placing the #id annotation above the getter. By placing my #id annotation above the getter I implicitly specified property-based access resulting in hibernate calling the getter and setter methods to access my attributes, hence why my #ManyToOne annotation had to be above the getter. The examples I was referencing placed the #id annotation above the class variable itself, implicitly specifying field-based access in which case you should placing the #ManyToOne annotation above the class variables work. Source

QueryDSL Predicate for use with JPARepository where field is a JSON String converted using an AttributeConverter to a List<Object>

I have a JPA Entity (Terminal) which uses an AttributeConverter to convert a Database String into a list of Objects (ProgrmRegistration). The converter just uses a JSON ObjectMapper to turn the JSON String into POJO objects.
Entity Object
#Entity
#Data
public class Terminal {
#Id
private String terminalId;
#NotEmpty
#Convert(converter = ProgramRegistrationConverter.class)
private List<ProgramRegistration> programRegistrations;
#Data
public static class ProgramRegistration {
private String program;
private boolean online;
}
}
The Terminal uses the following JPA AttributeConverter to serialize the Objects from and to JSON
JPA AttributeConverter
public class ProgramRegistrationConverter implements AttributeConverter<List<Terminal.ProgramRegistration>, String> {
private final ObjectMapper objectMapper;
private final CollectionType programRegistrationCollectionType;
public ProgramRegistrationConverter() {
this.objectMapper = new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
this.programRegistrationCollectionType =
objectMapper.getTypeFactory().constructCollectionType(List.class, Terminal.ProgramRegistration.class);
}
#Override
public String convertToDatabaseColumn(List<Terminal.ProgramRegistration> attribute) {
if (attribute == null) {
return null;
}
String json = null;
try {
json = objectMapper.writeValueAsString(attribute);
} catch (final JsonProcessingException e) {
LOG.error("JSON writing error", e);
}
return json;
}
#Override
public List<Terminal.ProgramRegistration> convertToEntityAttribute(String dbData) {
if (dbData == null) {
return Collections.emptyList();
}
List<Terminal.ProgramRegistration> list = null;
try {
list = objectMapper.readValue(dbData, programRegistrationCollectionType);
} catch (final IOException e) {
LOG.error("JSON reading error", e);
}
return list;
}
}
I am using Spring Boot and a JPARepository to fetch a Page of Terminal results from the Database.
To filter the results I am using a BooleanExpression as the Predicate. For all the filter values on the Entity it works well, but the List of objects converted from the JSON string does not allow me to easily write an Expression that will filter the Objects in the list.
REST API that is trying to filter the Entity Objects using QueryDSL
#GetMapping(path = "/filtered/page", produces = MediaType.APPLICATION_JSON_VALUE)
public Page<Terminal> findFilteredWithPage(
#RequestParam(required = false) String terminalId,
#RequestParam(required = false) String programName,
#PageableDefault(size = 20) #SortDefault.SortDefaults({ #SortDefault(sort = "terminalId") }) Pageable p) {
BooleanBuilder builder = new BooleanBuilder();
if (StringUtils.isNotBlank(terminalId))
builder.and(QTerminal.terminal.terminalId.upper()
.contains(StringUtils.upperCase(terminalId)));
// TODO: Figure out how to use QueryDsl to get the converted List as a predicate
// The code below to find the programRegistrations does not allow a call to any(),
// expects a CollectionExpression or a SubqueryExpression for calls to eqAny() or in()
if (StringUtils.isNotBlank(program))
builder.and(QTerminal.terminal.programRegistrations.any().name()
.contains(StringUtils.upperCase(programName)));
return terminalRepository.findAll(builder.getValue(), p);
}
I am wanting to get any Terminals that have a ProgramRegistration object with the program name equal to the parameter passed into the REST service.
I have been trying to get CollectionExpression or SubQueryExpression working without success since they all seem to be wanting to perform a join between two Entity objects. I do not know how to create the path and query so that it can iterate over the programRegistrations checking the "program" field for a match. I do not have a QProgamRegistration object to join with, since it is just a list of POJOs.
How can I get the predicate to match only the Terminals that have programs with the name I am searching for?
This is the line that is not working:
builder.and(QTerminal.terminal.programRegistrations.any().name()
.contains(StringUtils.upperCase(programName)));
AttributeConverters have issues in Querydsl, because they have issues in JPQL - the query language of JPA - itself. It is unclear what actually the underlying query type of the attribute is, and whether the parameter should be a basic type of that query type, or should be converted using the conversion. Such conversion, whilst it appears logical, is not defined in the JPA specification. Thus a basic type of the query type needs to be used instead, which leads to new difficulties, because Querydsl can't know the type it needs to be. It only knows the Java type of the attribute.
A workaround can be to force the field to result into a StringPath by annotating the field with #QueryType(PropertyType.STRING). Whilst this fixes the issue for some queries, you will run into different issues in other scenarios. For more information, see this thread.
Although the following desired QueryDsl looks like it should work
QTerminal.terminal.programRegistrations.any().name().contains(programName);
In reality JPA would never be able to convert it into something that would make sense in terms of SQL. The only SQL that JPA could convert it into could be as follows:
SELECT t.terminal_id FROM terminal t where t.terminal_id LIKE '%00%' and t.program_registrations like '%"program":"MY_PROGRAM_NAME"%';
This would work in this use case, but be semantically wrong, and therefore it is correct that it should not work. Trying to select unstructured data using a structured query language makes no sense
The only solution is to treat the data as characters for the DB search criteria, and to treat it as a list of Objects after the query completes and then perform filtering of the rows in Java. Although This makes the paging feature rather useless.
One possible solution is to have a secondary read only String version of the column that is used for the DB search criteria, that is not converted to JSON by the AttributeConverter.
#JsonIgnore
#Column(name = "programRegistrations", insertable = false, updatable = false)
private String programRegistrationsStr;
The real solution is do not use unstructured data when you want structured queries on that data Therefore convert the data to either a database that supports the JSON natively for queries or model the data correctly in DDL.
To have a short answer: the parameter used in the predicate on attribute with #QueryType must be used in another predicate on attribute of type String.
It's a clearly known issue describe in this thread: https://github.com/querydsl/querydsl/issues/2652
I simply want to share my experience about this bug.
Model
I have an entity like
#Entity
public class JobLog {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private String id;
#QueryType(PropertyType.STRING)
private LocalizedString message;
}
Issue
I want to perform some predicate about message. Unfortunately, with this configuration, I can't do this:
predicates.and(jobLog.message.likeIgnoreCase(escapedTextFilter));
because I have the same issues that all people!
Solution
But I find a way to workaround :)
predicates.and(
(jobLog.id.likeIgnoreCase(escapedTextFilter).and(jobLog.id.isNull()))
.or(jobLog.message.likeIgnoreCase(escapedTextFilter)));
Why it workaround the bug?
It's important that escapedTextFilter is the same in both predicate!
Indeed, in this case, the constant is converter to SQL in the first predicate (which is of String type). And in the second predicate, we use the conterted value
Bad thing?
Add a performance overflow because we have OR in predicate
Hope this can help someone :)
I've found one way to solve this problem, my main idea is to use mysql function cast(xx as char) to cheat hibrenate. Below is my base info. My code is for work , so I've made an example.
// StudentRepo.java
public interface StudentRepo<Student, Long> extends JpaRepository<Student, Long>, QuerydslPredicateExecutor<Student>, JpaSpecificationExecutor<Student> {
}
// Student.java
#Data
#AllArgsConstructor
#NoArgsConstructor
#EqualsAndHashCode(of = "id")
#Entity
#Builder
#Table(name = "student")
public class Student {
#Convert(converter = ClassIdsConvert.class)
private List<String> classIds;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
}
// ClassIdsConvert.java
public class ClassIdsConvert implements AttributeConverter<List<String>, String> {
#Override
public String convertToDatabaseColumn(List<String> ips) {
// classid23,classid24,classid25
return String.join(",", ips);
}
#Override
public List<String> convertToEntityAttribute(String dbData) {
if (StringUtils.isEmpty(dbData)) {
return null;
} else {
return Stream.of(dbData.split(",")).collect(Collectors.toList());
}
}
}
my db is below
id
classIds
name
address
1
2,3,4,11
join
北京市
2
2,31,14,11
hell
福建省
3
2,12,22,33
work
福建省
4
1,4,5,6
ouy
广东省
5
11,31,34,22
yup
上海市
-- ----------------------------
-- Table structure for student
-- ----------------------------
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
`id` int(11) NOT NULL,
`classIds` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
Use JpaSpecificationExecutor solve the problem
Specification<Student> specification = (root, query, criteriaBuilder) -> {
String classId = "classid24"
String classIdStr = StringUtils.wrap(classId, "%");
var predicate = criteriaBuilder.like(root.get("classIds").as(String.class), classIdStr);
return criteriaBuilder.or(predicate);
};
var students = studentRepo.findAll(specification);
log.info(new Gson().toJson(students))
attention the code root.get("classIds").as(String.class)
In my opinion, if I don't add .as(String.class) , hibernate will think the type of student.classIds is list and throw an Exception as below.
SQL will like below which runs correctly in mysql. But hibnerate can't work.
org.springframework.dao.InvalidDataAccessApiUsageException: Parameter value [%classid24%] did not match expected type [java.util.List (n/a)]; nested exception is java.lang.IllegalArgumentException: Parameter value [%classid24%] did not match expected type [java.util.List (n/a)]
SELECT
student0_.id AS id1_0_,
student0_.class_ids AS class_ids2_0_
FROM
student student0_
WHERE
student0_.class_ids LIKE '%classid24%' ESCAPE '!'
if you add .as(String.class) , hibnerate will think the type of student.classIds as string and won't check it at all.
SQL will be like below which can run correct in mysql. Also in JPA.
SELECT
student0_.id AS id1_0_,
student0_.class_ids AS class_ids2_0_
FROM
student student0_
WHERE
cast( student0_.class_ids AS CHAR ) LIKE '%classid24%' ESCAPE '!'
when the problem is solved by JpaSpecificationExecutor, so I think this can be solve also in querydsl. At last I find the template idea in querydsl.
String classId = "classid24";
StringTemplate st = Expressions.stringTemplate("cast({0} as string)", qStudent.classIds);
var students = Lists.newArrayList<studentRepo.findAll(st.like(StringUtils.wrap(classId, "%"))));
log.info(new Gson().toJson(students));
it's sql is like below.
SELECT
student0_.id AS id1_0_,
student0_.class_ids AS class_ids2_0_
FROM
student student0_
WHERE
cast( student0_.class_ids AS CHAR ) LIKE '%classid24%' ESCAPE '!'

How to add enum field in postgres?

In my model there is an enum field, trying to add an enum field to the database, but does not work, can you comment?
public class ChatMessage {
private MessageType messageType;
private String content;
private String sender;
public enum MessageType {
CHAT,
JOIN,
LEAVE
}
my postgre code
CREATE TYPE messageType AS ENUM ('CHAT', 'JOIN', 'LEAVE');
CREATE TABLE "chatMessage" (
id SERIAL UNIQUE PRIMARY KEY,
messageType messageType,
content VARCHAR(255) NOT NULL,
sender VARCHAR(255) NOT NULL
);
I suppose that I incorrectly declare the variable enum in postgres
Use Enumerated Annotation and Spring will handle this for you.
But in general Enums will be VARCHAR(X) in Postgres (see second link)
public class ChatMessage {
#Enumerated(EnumType.STRING)
private MessageType messageType;
private String content;
private String sender;
}
http://tomee.apache.org/examples-trunk/jpa-enumerated/
https://vladmihalcea.com/the-best-way-to-map-an-enum-type-with-jpa-and-hibernate/
If I get it right, according to the documentation your doing fine.
Although in their example they choose a different name for the column that references the Enum Type.
Try change it, like, messages messageType.
Another example: https://tapoueh.org/blog/2018/05/postgresql-data-types-enum/#postgresql-enum-data-type

JPA not returning the records which contain empty columns in the EmbeddedId

JpaRepository's findAll() method does not return the rows, if any of the field in the composite key is null.
This is the entity class with the EmbeddedId JobVaccinationPK
/**
* ApplicationParam entity. #author MyEclipse Persistence Tools
*/
#Entity
#Table(name="job_vaccination",schema="cdcis")
#SuppressWarnings("serial")
public class JobVaccination implements java.io.Serializable {
// Fields
#Column(name="default_yn", length=1)
private String defaultYn;
#EmbeddedId
private JobVaccinationPK jobVaccinationPK;
public JobVaccination(){
}
//setters getters
}
This is the Embedded class
#Embeddable
#SuppressWarnings("serial")
public class JobVaccinationPK implements Serializable{
#ManyToOne
#MapsId("job_category_id")
#JoinColumn(name = "job_category_id", nullable=true)
private JobCategoryTypeMast jobCategoryMast;
#ManyToOne
#MapsId("vaccination_id")
#JoinColumn(name = "vaccination_id", nullable=true)
private VaccinationMast vaccinationMast;
#ManyToOne
#MapsId("screening_type_id")
#JoinColumn(name = "screening_type_id", nullable=true)
private ScreeningTypeMast screeningTypeMast;
//getters and setters
}
Service implementation class
#Override
public SearchResult<JobVaccinationDto> getJobVaccination(JobVaccinationDto dto)
throws VaccinationException {
List<JobVaccination> vaccDetails = jobVaccinationRepo.findAll();
if(vaccDetails == null) return null;
List<JobVaccinationDto> jobVaccinationDtos = new ArrayList<JobVaccinationDto>();
jobVaccinationDtos = convertToDto(vaccDetails);
return new SearchResult<>(jobVaccinationDtos.size(), jobVaccinationDtos);
}
Here am able to insert a null value for either jobCategoryId or screeningTypeId, just like below row. But when I'm trying to fetch the rows which have empty values, it returns null. I've tried to debug but I was not able to find the cause.
This is the generated hibernate query:
Hibernate:
select
jobvaccina0_.job_category_id as job_cate4_13_,
jobvaccina0_.screening_type_id as screenin2_13_,
jobvaccina0_.vaccination_id as vaccinat3_13_,
jobvaccina0_.default_yn as default_1_13_
from
cdcis.job_vaccination jobvaccina0_
Hibernate:
select
jobcategor0_.job_category_id as job_cate1_11_0_,
jobcategor0_.job_category_name as job_cate2_11_0_,
jobcategor0_.job_category_name_ar as job_cate3_11_0_,
jobcategor0_.screening_type_id as screenin4_11_0_
from
cdcis.job_category_mast jobcategor0_
where
jobcategor0_.job_category_id=?
Hibernate:
select
screeningt0_.screening_type_id as screenin1_21_0_,
screeningt0_.active_yn as active_y2_21_0_,
screeningt0_.mmpid_required_yn as mmpid_re3_21_0_,
screeningt0_.screening_type as screenin4_21_0_
from
cdcis.screening_type_mast screeningt0_
where
screeningt0_.screening_type_id=?
Hibernate:
select
vaccinatio0_.vaccination_id as vaccinat1_27_0_,
vaccinatio0_.vaccination_name as vaccinat2_27_0_,
vaccinatio0_.vaccination_name_ar as vaccinat3_27_0_
from
cdcis.vaccination_mast vaccinatio0_
where
vaccinatio0_.vaccination_id=?
Going with #Adam Michalik answer. As a work-around I've introduced a new primary key field in the table, as we can't handle a null in the composite key.
Composite IDs cannot contain null values in any of the fields. Since the SQL semantics of NULL is that NULL <> NULL, it cannot be determined that a primary key (1, 2, NULL) is equal to (1, 2, NULL).
NULL means "no value" in SQL and its interpretation is up to you on a case-by-case basis. That's why SQL and JPA do not want to make assumptions that NULL = NULL and that a primary key containing a NULL identifies a single entity only.
You may choose to use a synthetic, generated primary key instead of the composite business primary key to overcome that. Then, you'd always have a non-null, single-column PK and nullable foreign keys.
change the data type of particular row in entity from int to integer

Resources