I have two Entity classes, each for my Table. They both are OneToOne-Mapped. When I read the Data, am always getting the other table's value as null.
These are my SQLs
CREATE TABLE driver_master (
unique_driver_id VARCHAR(60) PRIMARY KEY,
driver_name TEXT,
mobile_number VARCHAR (20),
vehicle_number TEXT,
vehicle_make TEXT,
seating_capacity INTEGER (10),
creation_time DATETIME
)
CREATE TABLE user_master (
user_id MEDIUMINT AUTO_INCREMENT PRIMARY KEY,
user_name TEXT,
password VARCHAR (20),
unique_driver_id VARCHAR(60),
FOREIGN KEY (unique_driver_id) REFERENCES driver_master(unique_driver_id)
)
These are my Entity classes
DriverMaster.java
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table(name = "driver_master")
public class DriverMaster {
#Id
#GeneratedValue(generator = "uuid2")
#GenericGenerator(name = "uuid2", strategy = "org.hibernate.id.UUIDGenerator")
#Column(name = "unique_driver_id")
UUID id;
#Column(name = "driver_name")
String driverName;
#Column(name = "mobile_number")
String mobileNumber;
#Column(name = "vehicle_number")
String vehicleNumber;
#Column(name = "vehicle_make")
String vehicleMake;
#Column(name = "seating_capacity")
Integer seatingCapacity;
#Column(name = "creation_time")
OffsetDateTime creationTime;
#OneToOne(cascade = CascadeType.ALL, mappedBy = "driverMaster")
UserMaster userMaster;
}
UserMaster.java
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table(name = "user_master")
public class UserMaster {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "user_id")
Long id;
#Column(name = "user_name")
String userName;
#Column(name = "password")
String password;
#OneToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "unique_driver_id", nullable = false)
DriverMaster driverMaster;
}
This is my DriverMasterRepository
public interface DriverMasterRepository extends CrudRepository<DriverMaster, Long> {
DriverMaster findById(UUID id);
}
This is my UserMasterRepository
public interface UserMasterRepository extends CrudRepository<UserMaster, Long> {
UserMaster findById(Long id);
}
I am creating DriverMaster and UserMaster at the same time. Code Snippet below
public DriverMaster create() {
UserMaster userMaster = UserMaster.builder()
.userName("xxxxx")
.password("xxxx").build();
DriverMaster driverMaster = DriverMaster.builder().driverName("TestDriver")
.creationTime(ZonedDateTime.now().toOffsetDateTime())
.seatingCapacity(8)
.mobileNumber("xxxxxxx")
.vehicleNumber("xxxx")
.vehicleMake("xxxx")
.userMaster(userMaster)
.build();
return driverUserService.create(driverMaster);
}
When i access each repository and get the data, the data for that particular table is getting populated while the referenced Object is always coming as Null.
After creation of DriverMaster, I couldn't get UserMaster within DriverMaster, it is always coming as null .
The REST Response below shows that UserMaster within DriverMaster is coming as Null
{
"id": "0d97073b-6ae2-47a9-b751-0313fd9e8ba2",
"driverName": "TestDriver",
"mobileNumber": "11111",
"vehicleNumber": "111",
"vehicleMake": "figo",
"seatingCapacity": 8,
"creationTime": "2018-02-16T15:56:50.331Z",
"userMaster": null
}
it's not a 100% problem's reason, but I believe you have to add an implementation of Serializableinterface into your entity classes.
Related
I'm developing an application that queries a database.
There are a few issues right now.
history.isPresent() == false when calling Optional<History> findByKeyEquals() intermittently. but value is exist on database
This is the information I got while tracking the issue.
All child entities are non-null.
In most cases, if the same function is re-executed, it is searched.
But sometimes it doesn't happen intermittently.
i think that i use incorrectly table relationship annotation (#OneToMany,#ManyToOne options..)
I want to solve this issue.
this is my code
History (Parent)
#Table(
indexes = {
#Index(columnList = "key", unique = true),
})
#Entity
#Getter
#ToString
#Audited
public class History implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(updatable = false, nullable = false, columnDefinition = "BIGINT UNSIGNED")
private Long id;
#Setter
#Column(nullable = false, columnDefinition = "CHAR(36)")
private String key = UUID.randomUUID().toString();
#Setter
#Temporal(TemporalType.TIMESTAMP)
#NotAudited
private Date started = new Date();
#Setter
#Temporal(TemporalType.TIMESTAMP)
#NotAudited
private Date finished;
#Setter
#OneToMany(
cascade = CascadeType.ALL,
fetch = FetchType.LAZY,
mappedBy = "history",
orphanRemoval = true)
#NotAudited
private List<Content> contents = new ArrayList<>();
...
}
Content (Child)
#Table
#Entity
#Getter
#Audited
public class Content implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(updatable = false, nullable = false, columnDefinition = "BIGINT UNSIGNED")
private Long id;
#Setter
#Column(columnDefinition = "LONGTEXT")
#NotAudited
private String content;
#Setter
#ManyToOne(targetEntity = History.class, fetch = FetchType.Lazy, optional = false)
#Audited
private History history;
...
}
Repository
public interface HistoryRepository
extends JpaRepository<History, Long>, RevisionRepository<History, Long, Integer> {
Optional<History> findByKeyEquals(final String key);
}
I have two entities : Article and Category
#AllArgsConstructor
#Entity
#ToString
#Table(name = "articles")
public class Article {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "title", nullable = false, unique = true)
private String title;
#Embedded
private Audit audit = new Audit();
#ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE})
#JoinTable(name = "articles_categories", joinColumns = {#JoinColumn(name = "articles_id")}, inverseJoinColumns = {#JoinColumn(name = "categories_id")})
#JsonManagedReference
private List<Category> categories = new ArrayList<>();
Now the entity Category
Then I have Category entity
#Getter
#Setter
#Accessors ( chain = true )
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table ( name = "category" )
public class Category {
#Id
#GeneratedValue ( strategy = GenerationType.IDENTITY )
#Column ( name = "id" )
private Long id;
#Column ( name = "name", nullable = false, unique = true )
private String name;
#ManyToMany ( fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST , CascadeType.MERGE }, mappedBy = "categories" )
#JsonBackReference
private Set<Article> categories = new HashSet<>();
}
And now the entity Embedded
#Getter
#Setter
#Embeddable
#RequiredArgsConstructor
public class Audit {
#Column ( name = "created_on" )
private Date createdOn;
#Column ( name = "updated_on" )
private Date updatedOn;
#PrePersist
public void prePersist ( ) {
createdOn = new Date ( );
}
#PreUpdate
public void preUpdate ( ) {
updatedOn = new Date ( );
}
}
In my article repository I have the following JPA.
#Repository
public interface ArticleRepository extends JpaRepository < Article, Long > {
Page<Article> findByCategoriesIn (List<Category> categories, Pageable pageable);
}
This works correctly and is returning a page of articles but I would like to order articles by creation date using #Embeeded annotation.
How could I use this ?
Try to use something like this:
Page<Article> findByCategoriesInOrderByAudit_CreatedOnDesc(List<Category> categories, Pageable pageable);
See also this and this sections of the documentation.
I've started to learn Spring Boot, I've created two entities Invoice and YearDate
When I try to search by year(id), in my log query I got null (see this part of log query)
http://localhost:8080/appapi/invoices/search/findByYearId?year=1
from invoice invoice0_ left outer join year_date yeardate1_ on invoice0_.year_id=yeardate1_.id where yeardate1_.id is null limit?
I'm using Lombok also for getters and setters
Here are all my class entities, SQL tables, and JpaRepository interface :
SQL foreign key :
KEY `fk_year` (`year_id`),
CONSTRAINT `fk_year` FOREIGN KEY (`year_id`) REFERENCES `YearDate` (`id`)
YearDate class :
#Entity
#Table(name="YearDate")
#Data
public class YearDate {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "year_value")
private String yearValue;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "year")
private Set<Invoice> invoices;
}
Invoice class:
#Entity
#Table(name="invoice")
#Data
public class Invoice {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "name")
private String name;
#ManyToOne
#JoinColumn(name = "year_id", nullable = false)
private YearDate year;
#Column(name = "description")
private String description;
}
**And The Invoice Interface:**
#CrossOrigin("http://localhost:4200")
public interface InvoiceRepository extends JpaRepository<Invoice, Long> {
Page<Invoice> findByYearId(#RequestParam("year") Long id, Pageable page);
}
Work for me.
try to extract call in rest controller and log params
#GetMapping(value = "/invoices")
public Page<Invoice> getInvoices(#RequestParam("yearId") Long yearId) {
Page<Invoice> byYearId = invoiceRepository.findByYearId(yearId, PageRequest.of(0, 10));
return byYearId;
}
public interface InvoiceRepository extends JpaRepository<Invoice, Long> {
Page<Invoice> findByYearId(Long id, Pageable page);
}
#ManyToOne
#JoinColumn(name = "year_id", nullable = false)
#JsonIgnoreProperties("invoices")
private YearDate year;
#OneToMany(mappedBy = "year")
#JsonIgnoreProperties("year")
private Set<Invoice> invoices;
Generated SQL :
Hibernate:
select
invoice0_.id as id1_0_,
invoice0_.description as descript2_0_,
invoice0_.name as name3_0_,
invoice0_.year_id as year_id4_0_
from
invoice invoice0_
left outer join
year_date yeardate1_
on invoice0_.year_id=yeardate1_.id
where
yeardate1_.id=? limit ?
Hibernate:
select
yeardate0_.id as id1_5_0_,
yeardate0_.year_value as year_val2_5_0_
from
year_date yeardate0_
where
yeardate0_.id=?
-> ADD #JsonIgnoreProperties("invoices") and #JsonIgnoreProperties("year") to entities to avoid infinite json recusrsion.
I've disabled Lombok and it works
try pass him a Year object not id is better
#CrossOrigin("http://localhost:4200")
public interface InvoiceRepository extends JpaRepository<Invoice, Long> {
Page<Invoice> findByYear(YearDate year, Pageable page);
}
and in your service get this year
for exemple I create a getYears method in service:
#Service
public class YearService{
#Autowired
private YearRepository yearRepository;
#Autowired
private InvoiceRepository invoiceRepository;
getYears(idYear:Long){
YearDate yearParam=yearRepository.findById(id).get();
Page<Invoice> invoices=invoiceRepository.findByYear(yearParam,YourPagination)
}
}
I would like to link a comment table and a film table with a user table. I wish to allow a user to have many comments, and a film have many comments. I then want to display a list of comments in a details page for each film, giving the option for the user who created the comment to delete or update it.
I altered my code in an attempt to create a one to many relation between comment and film, but I get the error:
Caused by: org.h2.jdbc.JdbcSQLException: NULL not allowed for column
"FILM_ID"; SQL statement: alter table film add column film_id bigint
not null [23502-196]
It makes me think two things:
1) Set to allow null or figure out why there is a null field. I attempted allow null by adding #Column(name = "film_id", nullable = true) but it said parameter is redundant.
2) Film table has auto incrementing ID already, so by adding #Column(name = "film_id") am I duplicating an ID? As with the error message saying "add column" it made me think so?
My attempt currently stands at:
Film.java
package com.demo.spring.domain;
import org.springframework.format.annotation.DateTimeFormat;
import javax.persistence.*;
import java.util.Date;
import java.util.List;
#Entity
public class Film {
#Id #GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "film_id", nullable = true)
Long id;
String title;
String director;
String description;
#DateTimeFormat(pattern="yyyy-MM-dd")
Date date;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "film_id", referencedColumnName = "film_id")
List<Comment> comments;
public List<Comment> getComments() {
return comments;
}
public void setComments(List<Comment> comments) {
this.comments = comments;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
//rest of getter and setters below//
Comment.java
package com.demo.spring.domain;
import javax.persistence.*;
#Entity
public class Comment {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "comment_id")
Long id;
String body;
#Column(name = "film_id")
Long filmId;
public Long getFilmId() {
return filmId;
}
public void setFilmId(Long filmId) {
this.filmId = filmId;
}
public Comment(){
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
}
UPDATE
I have changed Film.java..
From:
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "film_id", referencedColumnName = "film_id")
List<Comment> comments;
To:
#OneToMany(cascade = CascadeType.ALL)
List<Comment> comments;
And if I add in Comment.java:
#OneToMany(cascade=CascadeType.ALL)
#JoinTable(name="film", joinColumns=#JoinColumn(name = "film_id_fk", referencedColumnName = "film_id"))
private Set<Comment> comment = new HashSet<Comment>();
Film film;
I get:
MappingException: Foreign key
(FK5vk85sy54a8be115ye9ra1lyu:film_comments [film_film_id])) must have
same number of columns as the referenced primary key (film
[film_id_fk,comment_comment_id])
If I change private Set<Comment> comment = new HashSet<Comment>(); to List<Comment> comments = new ArrayList<Comment>(); I get:
NULL not allowed for column "FILM_ID"; SQL statement: alter table film
add column film_id bigint not null
And if instead I add:
#OneToMany(cascade=CascadeType.ALL)
#JoinColumn(name = "film_id_fk", referencedColumnName = "film_id")
private Set<Comment> comment = new HashSet<Comment>();
Film film;
I get:
MappingException: Could not determine type for:
com.demo.spring.domain.Film, at table: comment, for columns:
[org.hibernate.mapping.Column(film)]
If I change private Set<Comment> comment = new HashSet<Comment>(); to List<Comment> comments = new ArrayList<Comment>(); I get:
NULL not allowed for column "FILM_ID"; SQL statement: alter table film
add column film_id bigint not null
A primary key can't be null, so you can't make "film_id" nullable. And your #JoinColumn annotation is wrong, that goes on the #ManyToOne side. The name parameter should be the name of the foreign key column in the Comments table (so it can't be the same name as the primary key) and referencedColumnName should be the name of the column that you're referencing in the other table
#Entity
public class Film {
#Id #GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "film_id")
Long id;
String title;
String director;
String description;
#DateTimeFormat(pattern="yyyy-MM-dd")
Date date;
#OneToMany(cascade = CascadeType.ALL)
List<Comment> comments;
//...
}
#Entity
public class Comment {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "comment_id")
Long id;
String body;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "film_id_fk", referencedColumnName = "film_id")
Film film;
//...
}
I'm trying to implement a meeting model which contains multiple equipment entity with corresponding quantity.
In the view of meeting, user should be able to CRUD equipment and quantity of this equipment of a meeting
databases:
CREATE TABLE IF NOT EXISTS equipment (
equipment_id SERIAL PRIMARY KEY,
equipment_name VARCHAR(20) NOT NULL
);
CREATE TABLE IF NOT EXISTS meeting (
meeting_id SERIAL PRIMARY KEY,
meeting_time TIMESTAMP NOT NULL,
number_people INTEGER NOT NULL,
setup VARCHAR(255)
);
CREATE TABLE IF NOT EXISTS meeting_equipment (
meeting_equipment_id SERIAL PRIMARY KEY ,
meeting_id INTEGER NOT NULL REFERENCES meeting (meeting_id),
equipment_id INTEGER NOT NULL REFERENCES equipment (equipment_id),
quantity INTEGER NOT NULL DEFAULT 0
);
Entity implementation:
#Entity
#Table(name = "meeting")
#Data
public class Meeting {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "meeting_id", updatable = false)
#JsonIgnore
private int id;
#Column(name = "meeting_time")
#JsonFormat(pattern = "yyyy-MM-dd HH:mm")
#NotNull
private LocalDateTime meetingTime;
#Column(name = "number_people")
#NotNull
#Min(1)
private int numberPeople;
#Column(name = "setup")
#NotNull
private String setup;
#OneToMany(mappedBy = "meeting", cascade = CascadeType.ALL)
#JsonManagedReference
List<MeetingEquipment> equipmentList = new ArrayList<>();
}
#Entity
#Table(name = "equipment")
#Data
public class Equipment {
#Id
#Column(name = "equipment_id", updatable = false)
#JsonIgnore
private int id;
#NotNull
#Column(name = "equipment_name", unique = true)
#Size(min = 1, max = 100)
private String equipmentName;
}
Join table metting_equipment:
#Entity
#Table(name = "meeting_equipment", uniqueConstraints = {
#UniqueConstraint(columnNames = {"meeting_id", "equipment_id"})})
#Data
public class MeetingEquipment {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "meeting_equipment_id", updatable = false)
#JsonIgnore
private int id;
#ManyToOne
#JoinColumn(name = "meeting_id")
#NotNull
#JsonBackReference
private Meeting meeting;
#ManyToOne
#JoinColumn(name = "equipment_id")
#NotNull
private Equipment equipment;
#Column(name = "quantity")
#NotNull
private int quantity;
}
Using the code above, I can successfully create meeting with equipment included (JSON returned from creation method shows correct content). But once I try to remove an element of equipmentList in meeting entity, it does not delete meetingEquipment entity. I tried
meeting.getEquipmentList().clear() and meetingEquipmentDao.delete(meeting.getEquipmentList()), neither works.
Could anyone tell me the cause of this problem, thanks!