how to save entity with relationship in spring boot - java

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.

Related

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 bidrectional entity with dto

I have two spring boot entities MeetingSetting and MeetingTime, MeetingSetting can have multiple MeetingTimes. I am trying to save these to at the same time with the DTO structure, so I can avoid the circular reference problem when I am getting MeetingTimes. Saving partially works. MeetingSettings has a property called meetingName which is a foreign key in meetingTimes. Everything except meetingName is saved which is for some reason null, but I can not find the reason, could someone maybe look at my code and tell me what I am missing?
MeetingSetting Entity:
#Entity
#Table(name = "meeting_settings")
#Setter
#Getter
public class MeetingsSetting implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "meeting_name", unique = true)
private String meetingName;
#Column(name = "meeting_url")
private String meetingUrl;
#Column(name = "meeting_pw")
private String meetingPw;
#OneToMany(mappedBy = "meetingName", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set<MeetingTime> meetingTime = new HashSet<>();
}
MeetingSettingDTO:
#Getter
#Setter
public class MeetingSettingDTO {
private Long id;
#NotNull
private String meetingName;
#NotNull
private String meetingUrl;
#NotNull
private String meetingPw;
private Set<MeetingTime> meetingTime;
}
MeetingTime Entity:
#Entity
#Table(name = "meeting_times")
#Getter
#Setter
public class MeetingTime implements Serializable {
#JsonIgnore
#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(fetch = FetchType.LAZY)
#JoinColumn(name = "meeting_name" , referencedColumnName = "meeting_name")
private MeetingsSetting meetingName;
}
MeetingTimeDTO:
#Getter
#Setter
public class MeetingTimeDTO {
private Long id;
#NotNull
private String date;
#NotNull
private String startTime;
#NotNull
private String endTime;
private Set<MeetingSettingDTO> meetingSettings;
}
And finally the controller where I am saving everything (Just save method):
#PostMapping("/")
public void saveMeeting(#RequestBody MeetingSettingDTO meetingSettingDTO){
MeetingsSetting meetingsSetting = new MeetingsSetting();
meetingsSetting.setMeetingName(meetingSettingDTO.getMeetingName());
meetingsSetting.setMeetingPw(meetingSettingDTO.getMeetingPw());
meetingsSetting.setMeetingUrl(meetingSettingDTO.getMeetingUrl());
Set<MeetingTime> meetingTimeSet = meetingSettingDTO.getMeetingTime();
meetingsSetting.setMeetingTime(meetingTimeSet);
meetingSettingService.saveMeeting(meetingsSetting);
}
My service is just implementing a jpaRepository which takes MeetingSetting as parameter
In your MeetingTime entity class you have a parent:
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "meeting_name" , referencedColumnName = "meeting_name")
private MeetingsSetting meetingName;
You have to set it explicitly for each MeetingTime, so add this:
Set<MeetingTime> meetingTimeSet = meetingSettingDTO.getMeetingTime();
meetingTimeSet.forEach(m -> m.meetingName(meetingsSetting));

how to save entities in a relation to database in spring boot

I have a spring boot application with two entities in a relationship. MeetingSetting and MeetingTime meetingSetting can have unlimited meetingTimes. So far the databases are generating without problem, but When I try to save my Entity they are saved but different from each other, they are saved independently. Meaning MeetingName which is a foreign key inside MeetingTime is not saved but seen as null (I debugged and tried finding out why but could not find anything) THe other values are saved-
could someone point me out what my error is?
this is the json I am sending:
{
"meetingName":"TEst",
"meetingPw":"",
"meetingTime":[
{
"date":"2021-05-31",
"startTime":"15:30",
"endTime":"16:30"
},
{
"date":"2021-06-21",
"startTime":"15:30",
"endTime":"17:30"
},
{
"date":"2021-06-21",
"startTime":"11:01",
"endTime":"11:01"
}
]
}
MeetingSettings:
#Entity
#Table(name = "meeting_settings")
#Data
public class MeetingsSetting {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "meeting_name", unique = true)
private String meetingName;
#Column(name = "meeting_url")
private String meetingUrl;
#Column(name = "meeting_pw")
private String meetingPw;
#OneToMany(mappedBy = "meeting_Name", cascade = CascadeType.ALL)
private Set<MeetingTime> meetingTime = new HashSet<>();
}
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
#JoinColumn(name = "meeting_name" ,insertable = false, updatable = false , referencedColumnName = "meeting_name")
private MeetingsSetting meeting_Name;
}
this is how I try to save the entity:
#RestController
#RequestMapping("/api/meetingSetting")
public class MeetingSettingController {
#Autowired
MeetingSettingService meetingSettingService;
#PostMapping("/")
public void saveMeeting(#RequestBody MeetingsSetting meetingsSetting){
meetingSettingService.saveMeeting(meetingsSetting);
}
}
My service calls the save method of an jpaRepository.
In a bi-directional One to Many, you have to synchronize both sides of the association.
You can simply iterate over all MeetingTime objects and set the corresponding MeetingSetting to it.
Your MeetingSettingService's saveMeeting method could do this:
public void saveMeeting(MeetingsSetting meetingsSetting) {
// ...
// here you're synchronizing both sides of the association
meetingsSetting.getMeetingTime()
.forEach(mt -> mt.setMeetingSetting(meetingSetting));
// ...
repository.save(meetingSetting);
}
Solution to my question, I am not sure if this is a good or correct way of solving this maybe someone can advice me a better solution:
#Entity
#Table(name = "meeting_times")
#Data
public class MeetingTime implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "meeting_date")
private String date;
#Column(name = "start_time")
private String startTime;
#Column(name = "meeting_name")
private String meeting_name;
THIS IS THE PART WHICH IS CALLED FROM THE METHOD INSIDE MEETINGSCONTROLLER
#Column(name = "end_time")
private String endTime;
#ManyToOne
#JoinColumn(name = "meeting_name" ,insertable = false, updatable = false, referencedColumnName = "meeting_name")
private MeetingsSetting meetingName;
}
MeetingsTime Entity:
#RestController
#RequestMapping("/api/meetingSetting")
public class MeetingSettingController {
#Autowired
MeetingSettingService meetingSettingService;
#PostMapping("/")
public void saveMeeting(#RequestBody MeetingsSetting meetingsSetting){
meetingsSetting.getMeetingTime()
.forEach(mt -> mt.setMeeting_name(meetingsSetting.getMeetingName()));
// ...
meetingSettingService.saveMeeting(meetingsSetting);
}
}

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

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?

Referential integrity constraint violation error in JPA

I am trying to parse a web request and save to database. I have 3 models and first node is virtualDocument. This is the uniq table (according to request url). VirtualRequest table has all erquest bodies and HttpHeaderList table has all thhp headers according to their virtualRequest bean id.
when I tried to save the first log I got and error like this;
org.h2.jdbc.JdbcSQLException: Referential integrity constraint violation: "FK1TW2G47F7A47580KQVMDJWGBQ: PUBLIC.T_VIRTUAL_REQUEST FOREIGN KEY(REQUEST_ID) REFERENCES PUBLIC.T_VIRTUAL_DOCUMENT(DOCUMENT_ID) (65)"; SQL statement:
insert into t_virtual_request (request_id, media_type, method_type, request_url) values (null, ?, ?, ?) [23506-192]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:345) ~[h2-1.4.192.jar:1.4.192]
here is VirtualDocument bean
#Entity
#Table(name = "t_virtual_document")
public class VirtualDocument {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "document_id")
private long documentId;
#Column(name = "real_url", unique = true)
private String realURL; //uniq
#Column(name = "virtual_url", unique = true)
private String virtualURL; //uniq
#Column(name = "simulation_mode", columnDefinition = "varchar(10) default 'STOP'")
private String simulationMode;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "request_id")
private List<VirtualRequest> requestList;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "response_id")
private List<VirtualResponse> responseList;
//getter setter without any annotation
}
here is VirtualRequest bean;
#Entity
#Table(name = "t_virtual_request")
public class VirtualRequest {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "request_id")
private long requestId;
#Column(name = "request_url")
private String requestURL;
#Column(name = "method_type")
private String methodType;
#Column(name = "media_type")
private String mediaType;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "header_id")
private List<HttpHeaderList> requestHeaders;
//getter setter without any annotation
}
here is HeaderList bean;
#Entity
#Table(name = "t_http_headers")
public class HttpHeaderList {
#Id
#Column(name = "header_id")
private long headerId;
#Column(name = "header_key")
private String headerKey;
#Column(name = "header_value")
private String headerValue;
}
I think this is what you want instead:
#Entity
#Table(name = "t_virtual_document")
public class VirtualDocument {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "document_id")
private long documentId;
#Column(name = "real_url", unique = true)
private String realURL; //uniq
#Column(name = "virtual_url", unique = true)
private String virtualURL; //uniq
#Column(name = "simulation_mode", columnDefinition = "varchar(10) default 'STOP'")
private String simulationMode;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "virtualDocument")
private List<VirtualRequest> requestList;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "virtualDocument")
// Note the mappedBy parameter. This points to the property in the entity that owns the relationship (in this case the VirtualResponse).
private List<VirtualResponse> responseList;
//getter setter without any annotation
}
#Entity
#Table(name = "t_virtual_request")
public class VirtualRequest {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "request_id")
private long requestId;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "document_id")
private VirtualDocument virtualDocument;
#Column(name = "request_url")
private String requestURL;
#Column(name = "method_type")
private String methodType;
#Column(name = "media_type")
private String mediaType;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "virtualRequest")
private List<HttpHeaderList> requestHeaders;
//getter setter without any annotation
}
#Entity
#Table(name = "t_http_headers")
public class HttpHeader { /*Note this is a more appropriate name for the entity since it holds the data of a single header.*/
#Id
#Column(name = "header_id")
private long headerId;
#Column(name = "header_key")
private String headerKey;
#Column(name = "header_value")
private String headerValue;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "request_id")
private VirtualRequest virtualRequest
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "response_id")
private VirtualResponse virtualResponse;
}
Updated the answer to add mapping the headers to the request entity.

Categories

Resources