JPA and Hibernate: Entity with composite primary key using multiple #Id - java

I'm using SpringBoot with JPA and Hibernate.
For a specific entity I need to use a primary key composed by a relationship + a field.
Something like this:
#Entity
#Table(
name = "book",
uniqueConstraints=#UniqueConstraint(columnNames={"book_id",
"field_a"}))
public class Book extends MyBaseEntity {
#Id
#Column(name = "id")
#Type(type = "uuid-char")
private UUID uuid = UUID.randomUUID();
#Column(name = "name", nullable = false)
private String name;
#OneToMany(mappedBy = "book")
private List<Author> authors = new ArrayList<>();
}
#Entity
#Table(name = "author")
#IdClass(CustomID.class)
public class Author extends MyBaseEntity {
/* Here the composite key */
#Id
#ManyToOne()
#JoinColumn(name = "book_id")
private Book book;
#Id
#Column(name = "field_a", nullable = false)
#Type(type = "uuid-char")
private UUID fieldA;
#CreationTimestamp
#Column(name = "creation_date")
private Instant creationDate;
#UpdateTimestamp
#Column(name = "last_mod_date")
private Instant lastModificationDate;
}
public class CustomID implements Serializable {
private UUID book;
private UUID fieldA;
}
Using this approach, after some inserts on the DB, for Author entity book_id column contains values like these:
ÃFË5ÊL©T¾Äd
Why? Why there aren't Book primary keys values?

Related

How to retrieve ONE column from another table with Foreign key using Hibernate / JPA

I would like to use the Foreign key "MODEL_ID" to retrieve just one column "MODEL_NAME" from the TT_CARS table,
I tried the following code, that works but it returns the whole CARS object.
#JoinColumn(name = "MODEL_ID", referencedColumnName = "ID")
#ManyToOne(fetch = FetchType.EAGER)
private CARS cars;
Also I tried the code below, its also not working
#SecondaryTable(name = "TT_CARS", pkJoinColumns = #PrimaryKeyJoinColumn(name = "ID", referencedColumnName="MODEL_ID"))
Is there other way to retieve just the column (MODEL_NAME) using hibernate and JPA??
remarks: The modelName should be part of the Options class.
my code
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
#Entity
#Table(name = "TT_OPTIONS")
public class Options {
#Id
#Column(name = "ID")
private String id;
#NotNull
#Column(name = "DESCRIPTION", nullable = false)
private String description;
#Column(name = "MODEL_ID") // Foreign key
private Long modelId;
#Column(name = "MODEL_NAME", table = "TT_CARS") // this is the column name I would like to retrieve from the TT_CARS table
private String modelName;
// getters and setters
}
You can use #Formula. It is read-only calculated column that can be retrieved by the custom subquery. It does not present in the target table.
Defines a formula (derived value) which is a SQL fragment that acts as
a #Column alternative in most cases. Represents read-only state.
Example:
#Entity
#Table(name = "TT_OPTIONS")
public class Options {
#Id
#Column(name = "ID")
private Long id;
#Column(name = "DESCRIPTION", nullable = false)
private String description;
#Column(name = "MODEL_ID")
private Long modelId;
#Formula("(select TT_CARS.MODEL_NAME from TT_CARS where TT_CARS.ID = MODEL_ID)")
private String modelNameFormula;
}
#Entity
#Table(name = "TT_CARS")
public class Cars {
#Id
#Column(name = "ID")
private Long id;
#Column(name = "MODEL_NAME")
private String modelName;
}
Hibernate generated native query:
select
options0_.id as id1_4_0_,
options0_.description as descript2_4_0_,
options0_.model_id as model_id3_4_0_,
(select
TT_CARS.MODEL_NAME
from
TT_CARS
where
TT_CARS.ID = options0_.MODEL_ID) as formula1_0_
from
tt_options options0_
where
options0_.id=?
#SecondaryTable designed for #OneToOne relationship to map multiple tables to the same entity. It will not work for the #ManyToOne relationship.

JPA entity with join column but not persisted

I have to entities
#Table(name = "BD_PERSON")
public class DBPerson {
#Id
#Column(name = "persion_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "name")
private String name;
#Column(name = "car_id")
private Long car_id;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "car_id", referencedColumnName = "car_id", insertable = false, updatable = false)
private DBCar car;
#Column(name = "label")
private String label;
and
#Table(name = "BD_CAR")
public class DBCar {
#Id
#Column(name = "car_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "car_number")
private Integer carNumber;
#Column(name = "description")
private String description;
I want to be able to get the Person with the car entity but this should not persist to the database when updating.
But i should be able to update the car_id by itself as it relates the the id in the car table.
but when i try to test this by setting only the car_id i receive an Referential integrity constraint violation.
Because the car_id (FK)references the car_id (PK)
Is there any better way to accomplish what im trying to do?
The database already exists and is configured like this where the car_id is not an actual foreign key

how to save entity with relationship in spring boot

I have a spring boot application where I want to send an json object with a relationship. I have one entity called meetingSetting and one called meetingTime. MeetingSetting can have as many meetingTimes as possible and one meetingTime object belongs to one meetingSetting. But when I try to send it I am getting the following error:
not-null property references a null or transient value : com.cbc.coorporateblinddateservice.entities.dates.MeetingTime.meetingsSetting
I tried debugging and noticed that meetingSetting is empty when it is sent inside the times object send in the json. Could someone look at my code and tell me what I am missing, my guess is that I have to extend my saveMethod in meetingSettings but it is just a guess.
here is my MeetingSetting entity:
#Entity
#Table(name = "meeting_settings")
#Data
public class MeetingsSetting {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "meeting_name")
private String meetingName;
#Column(name = "meeting_url")
private String meetingUrl;
#Column(name = "meeting_pw")
private String meetingPw;
#OneToMany(mappedBy = "meetingsSetting", cascade = CascadeType.ALL)
private Set<MeetingTime> meetingTime = new HashSet<>();
}
meetingTime entity:
#Entity
#Table(name = "meeting_times")
#Data
public class MeetingTime {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "meeting_date")
private String date;
#Column(name = "start_time")
private String startTime;
#Column(name = "end_time")
private String endTime;
#ManyToOne()
#JoinColumn(name = "meeting_settings_name", nullable = false)
private MeetingsSetting meetingsSetting;
}
MeetingSettingCOntroller:
#RestController
#RequestMapping("/api/meetingSetting")
public class MeetingSettingController {
#Autowired
MeetingSettingService meetingSettingService;
#PostMapping("/")
public void saveMeeting(#RequestBody MeetingsSetting meetingsSetting){
meetingSettingService.saveMeeting(meetingsSetting);
}
Service:
#Service
public class MeetingSettingService {
#Autowired
MeetingSettingRepository meetingSettingRepository;
public void saveMeeting(#RequestBody MeetingsSetting meetingsSetting){
meetingSettingRepository.save(meetingsSetting);
}
Update new code:
MeetingTime:
#Entity
#Table(name = "meeting_times")
#Data
public class MeetingTime {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "meeting_date")
private String date;
#Column(name = "start_time")
private String startTime;
#Column(name = "end_time")
private String endTime;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "meeting_name", nullable = false)
private MeetingsSetting meetingName;
}
MeetingSettings:
#Entity
#Table(name = "meeting_settings")
#Data
public class MeetingsSetting {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "meeting_name")
private String meetingName;
#Column(name = "meeting_url")
private String meetingUrl;
#Column(name = "meeting_pw")
private String meetingPw;
#OneToMany(mappedBy = "meetingName", cascade = CascadeType.ALL)
private Set<MeetingTime> meetingTime = new HashSet<>();
}
Sql script:
create table meeting_times
(
id bigint auto_increment
primary key,
meeting_date varchar(255) null,
start_time varchar(255) null,
end_time varchar(255) null,
meeting_name varchar(255) null,
constraint fk_meeting_times__meeting_settings_name
foreign key (meeting_name) references meeting_settings (meeting_name)
);
The reason you're getting a null issue is that on #JoinColumn(name = "meeting_settings_name", nullable = false) you've got nullable = false. the column you're joining on is meeting_settings_name which doesn't seem to be a column on meeting_times and the actual name on meeting_settings is meeting_name. You'll have to add meeting_name to meeting_times to create a relation between the two tables to get this to work.

JPA composite key one to may relationship separate table

I am working on mapping a relationship using a composite key, but the composite key is a separate table.
Car Table
car Id
car description
car Value
SafetyReport Table
safetyReport Id
safetyReport Date
safetyReport Value
CompositeKey CarSafetyReport Table
carid
safetyReportId
One To Many: A car will have many safety reports
JPA:
#Data
#Entity
#Table(name = "CarTable")
public class CarEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "CarId", nullable = false)
private int carId;
#Column(name = "CarDescription", nullable = false)
private String carDescription;
#Column(name = "CarValue", nullable = false)
private String carDescription;
}
#Data
#Entity
#Table(name = "SafetyReport")
public class SafetyReportEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "SafetyReportId", nullable = false)
private int SafetyReportID;
#Column(name = "SafetyReportDate", nullable = false)
private OffsetDataTime date;
#Column(name = "SafetyReportValue", nullable = false)
private String safetyReportValue;
}
#Data
#Entity
#Table(name = "CarSafetyReport")
public class CarSafetyReportEntity implements Serializable {
#EmbeddedId
private CarSafetyReportPk id;
}
#Data
#AllArgsConstructor
#NoArgsConstructor
#Embeddable
public class CarSafetyReportPk implements Serializable {
#Column(name = "CarId", nullable = false)
private int carId;
#Column(name = "SafetyReportId", nullable = false)
private int SafetyReportId;
}
I tried
public class CarEntity {
#OneToMany(mappedBy = "id.carId" )
private List<CarSafetyReportEntity> carSafetyReportEntity;
}
I also tried putting the relationship in the composite key CarSafetyReportPk but i got an error for the annotation #OneToMany in a composite key.

Mapping a database view entity with a simple entity and pass to DTO using Spring Data

I'm just learning Spring Data. I want to map a database view Entity with a simple Entity and pass to DTO which will contain columns both entities. I understand that I can use a special database view but I need to map precisely entities of Spring Data.
I have a database view Entity "MentorStudents":
#Entity
#Table(name = "mentor_students")
#Immutable
public class MentorStudents implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "mentor_id", updatable = false, nullable = false)
private Long mentorId;
//This entity I need to map
private Mentor mentor;
#Column(name = "active_students")
private Integer activeStudents;
public MentorStudents() {
}
//getters, setters, equals, hashCode
}
A database view sql of an above entity is:
SELECT id AS mentor_id, active_students
FROM mentor
LEFT JOIN ( SELECT mentor_id, count(mentor_id) AS active_students
FROM contract
WHERE close_type IS NULL
GROUP BY mentor_id) active ON mentor.id = active.mentor_id
ORDER BY mentor.id;
And I have a simple Entity "Mentor":
#Entity
#Table(name = "mentor")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Mentor implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
private Long id;
#NotNull
#Column(name = "first_name", nullable = false)
private String firstName;
#NotNull
#Column(name = "last_name", nullable = false)
private String lastName;
#Column(name = "patronymic")
private String patronymic;
#Column(name = "phone")
private String phone;
#NotNull
#Column(name = "email", nullable = false)
private String email;
#Column(name = "skype")
private String skype;
#Column(name = "country")
private String country;
#Column(name = "city")
private String city;
#Column(name = "max_students")
private Long maxStudents;
//getters, setters, equals, hashCode
I have to get a DTO which contains all Mentor fields and an "activeStudents" MentorStudents field without a "mentorId" field. How do it?
Use spring data projection:
public interface YourDto {
// all Mentor get fields
String getFirstName();
...
// activeStudents get field
Integer getActiveStudents();
}
public interface YourRepository extends JpaRepository<YourEntity, Integer> {
#Query(value = "select ...(all fields match YourDto) from Mentor m, MentorStudents s where m.id = s.mentorId and m.id = ?1")
Optional<YourDto> findMyDto(Integer mentorId);
}

Categories

Resources