How do I create a sub table in spring boot? - java

The outcome I am looking for is: User writes a date, exercise name and times of exercise done. But the user can add more exercise and the amount of time done but the date stays the same. I am using spring boot maven, MySQL and reactjs if thats relevant.
date: 21-01-2021, exercise: push up, amount: 10, exercise: squats, amount:40
something like that.
#Entity
#Table(name="fitnessTracker")
public class User {
#Id
#GeneratedValue
private Long id;
private String username;
private Integer Date;
public Integer getDate() {
return Date;
}
public void setDate(Integer date) {
Date = date;
}
private String exercise;
private Integer amount;
public Integer getAmount() {
return amount;
}
public void setAmout(Integer amount) {
this.amount = amount;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getExercise() {
return exercise;
}
public void setExercise(String exercise) {
this.exercise = exercise;
}
}
I have tried searching in youtube and google but I cant find what I am looking for.

Change the table name to user instead of fitnessTracker.
Create a separate entity name FitnessTracker with fields as
#Entity
#Table(name="fitnessTracker")
public class FitnessTracker {
#Id
#GeneratedValue
private Long id;
private Date date;
private String exercise;
private int times;
#ManyToOne
#JoinColumn(name="id", nullable=false)
private User user;
}
Take a look at hibernate mappings https://www.baeldung.com/hibernate-one-to-many

Related

Unable to retrieve data from MySQL using Spring boot JPA

I am getting a java.lang.NullPointerException error at the line where the program begins to retrieve data from the database, specifically starting with the code recordDB.setAccountName(billing.getAccountId().getAccountName());. The entity tables are joined together and at first I thought that it can't retrieve data from other other tables but I tried to run with just recordDB.setAmount(billing.getAmount()); Can someone explain what I missed or is there something wrong with the logic?
Component
#Component
public class FileProcessor {
#Autowired
private BillingRepository billingRepository;
public FileProcessor() {
}
public List<Record> retrieveRecordfromDB(List<Request> requests) throws BarsException{
List<Record> records = new ArrayList<>();
if (!requests.isEmpty()) {
for (Request request : requests) {
Billing billing = billingRepository
.findByBillingCycleAndStartDateAndEndDate(
request.getBillingCycle()
, request.getStartDate()
, request.getEndDate());
if (billing == null) {
throw new BarsException(BarsException.NO_RECORDS_TO_WRITE);
}
Record recordDB = new Record();
recordDB.setBillingCycle(request.getBillingCycle());
recordDB.setStartDate(request.getStartDate());
recordDB.setEndDate(request.getStartDate());
recordDB.setAccountName(billing.getAccountId().getAccountName());
recordDB.setFirstName(billing.getAccountId().getCustomerId().getFirstName());
recordDB.setLastName(billing.getAccountId().getCustomerId().getLastName());
recordDB.setAmount(billing.getAmount());
records.add(recordDB);
}
}
return records;
}
}
Account Entity
#Entity
public class Account {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "account_id")
private int accountId;
private String accountName;
private LocalDateTime dateCreated;
private String isActive;
private String lastEdited;
public Account() {
}
public int getAccountId() {
return accountId;
}
public void setAccountId(int accountId) {
this.accountId = accountId;
}
public String getAccountName() {
return accountName;
}
public void setAccountName(String accountName) {
this.accountName = accountName;
}
public LocalDateTime getDateCreated() {
return dateCreated;
}
public void setDateCreated(LocalDateTime dateCreated) {
this.dateCreated = dateCreated;
}
public String getIsActive() {
return isActive;
}
public void setIsActive(String isActive) {
this.isActive = isActive;
}
public String getLastEdited() {
return lastEdited;
}
public void setLastEdited(String lastEdited) {
this.lastEdited = lastEdited;
}
public Customer getCustomerId() {
return customerId;
}
public void setCustomerId(Customer customerId) {
this.customerId = customerId;
}
public Set<Billing> getBilling() {
return billing;
}
public void setBilling(Set<Billing> billing) {
this.billing = billing;
}
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "customer_id")
private Customer customerId;
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "account_id")
private Set<Billing> billing;
}
Billing Entity
#Entity
public class Billing {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "billing_id")
private int billingId;
//private int billingId;
private int billingCycle;
private String billingMonth;
private Double amount;
private LocalDate startDate;
private LocalDate endDate;
private String lastEdited;
//private Account accountId;
public Billing() {
}
public int getBillingId() {
return billingId;
}
public void setBillingId(int billingId) {
this.billingId = billingId;
}
public int getBillingCycle() {
return billingCycle;
}
public void setBillingCycle(int billingCycle) {
this.billingCycle = billingCycle;
}
public String getBillingMonth() {
return billingMonth;
}
public void setBillingMonth(String billingMonth) {
this.billingMonth = billingMonth;
}
public Double getAmount() {
return amount;
}
public void setAmount(Double amount) {
this.amount = amount;
}
public LocalDate getStartDate() {
return startDate;
}
public void setStartDate(LocalDate startDate) {
this.startDate = startDate;
}
public LocalDate getEndDate() {
return endDate;
}
public void setEndDate(LocalDate endDate) {
this.endDate = endDate;
}
public String getLastEdited() {
return lastEdited;
}
public void setLastEdited(String lastEdited) {
this.lastEdited = lastEdited;
}
public Account getAccountId() {
return accountId;
}
public void setAccountId(Account accountId) {
this.accountId = accountId;
}
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "account_id")
private Account accountId;
}
Customer Entity
#Entity
public class Customer {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "customer_id")
private int customerId;
private String firstName;
private String lastName;
private String address;
private String status;
private LocalDateTime dateCreated;
private String lastEdited;
public Customer() {
}
public int getCustomerId() {
return customerId;
}
public void setCustomerId(int customerId) {
this.customerId = customerId;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public LocalDateTime getDateCreated() {
return dateCreated;
}
public void setDateCreated(LocalDateTime dateCreated) {
this.dateCreated = dateCreated;
}
public String getLastEdited() {
return lastEdited;
}
public void setLastEdited(String lastEdited) {
this.lastEdited = lastEdited;
}
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "customer_id")
private Set<Account> account;
}
Repository
#Repository
public interface BillingRepository extends JpaRepository<Billing, Integer> {
public Billing findByBillingCycleAndStartDateAndEndDate (int billingCycle, LocalDate startDate, LocalDate endDate);
}
Your naming is unintuitive, which hinders people unfamiliar with the code:
recordDB implies that it is the Database for records. Instead, it is a record that is to be saved in the DB. Naming it "RecordToSave" or similar is much better, since it gets the intention across.
getAccountId() implies that the id of an account is returned (an int or long) NOT that the account itself is returned. You should rename it to getAccount()
About the issue:
What you are using as a bidirectional ManyToOne <-> OneToMany relationship.
One side should be the owning side of the relationship. Here the #JoinColumn should be stated. The receiving end should have a MappedBy Property.
See this guide for more information: https://thorben-janssen.com/hibernate-tips-map-bidirectional-many-one-association/
It should solve the issue, since only the data retrieval for connected tables does not seem to work, hence fixing the references should fix the issue.
Your billing.getAmount() does refer to data written in the billing object/table, and is not from another table like billing.getAccountId().getAccountName() which gets data from the account table connected to the billings table.
Last, but not least:
Think about your cascading strategy. The way it currently works, deleting a billing will delete the account of that billing, which deletes all references made there and so on since you currently use Cascade.All for ALL entries. This is bad.
Here is a guide for cascading: https://howtodoinjava.com/hibernate/hibernate-jpa-cascade-types/
Are you sure the field names in the Billing class exactly match the database column names? I see you set the column name to "billing_id" explicitly for the id field, but not for any other fields. My guess is that the fields in that class are all null since there are no corresponding database columns (debug to confirm).

How to import data from one table to another - SpringBoot JPA /MySQL

I recently created a vehicle management system
The system is derived from MySQL database and server side in spring
I want to create another table (automatically at runtime) that will display only 2 of the columns of the existing table.
And the question is what am I doing wrong?
Final goal - when adding / deleting / editing a vehicle, both tables will work in sync and without collisions
I would be happy for your help
Below is the "Car" class
import javax.persistence.*;
import java.time.LocalDate;
#Entity
#Table(name = "car")
public class Car {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long carId;
private String licensePlate;
private int carType;
private boolean suv;
private int engineCapacity;
private int year;
private String note;
private int status;
private LocalDate careDate;
private LocalDate editDate;
public Car() {
}
public Car(long carId) {
this.carId = carId;
}
public long getCarId() {
return carId;
}
public void setCarId(long carId) {
this.carId = carId;
}
public String getLicensePlate() {
return licensePlate;
}
public void setLicensePlate(String licensePlate) {
this.licensePlate = licensePlate;
}
public int getCarType() {
return carType;
}
public void setCarType(int carType) {
this.carType = carType;
}
public boolean isSuv() {
return suv;
}
public void setSuv(boolean SUV) {
this.suv = SUV;
}
public int getEngineCapacity() {
return engineCapacity;
}
public void setEngineCapacity(int engineCapacity) {
this.engineCapacity = engineCapacity;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public LocalDate getCareDate() {
return careDate;
}
public void setCareDate(LocalDate careDate) {
this.careDate = careDate;
}
public LocalDate getEditDate() {
return editDate;
}
public void setEditDate(LocalDate editDate) {
this.editDate = editDate;
}
}
And CarType class which need only to create another MySQL table with the related columns (car_id and car_type)
package com.example.CarSystemMatanElbaz.model;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
#Entity
public class CarType {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#OneToOne(cascade = CascadeType.ALL,fetch = FetchType.LAZY,orphanRemoval = true)
#JoinColumn(name= "car_id")
private Car carId;
#OneToOne(cascade = CascadeType.ALL,fetch = FetchType.LAZY,orphanRemoval = true)
#JoinColumn(name= "car_type")
private Car carType;
public CarType() {
}
public CarType(long id, Car carId, Car carType) {
this.id = id;
this.carId = carId;
this.carType = carType;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public Car getCarId() {
return carId;
}
public void setCarId(Car carId) {
this.carId = carId;
}
public Car getCarType() {
return carType;
}
public void setCarType(Car carType) {
this.carType = carType;
}
}
Instead of checking and managing flow on the server-side. Just create Replicated Audit Table and making 3 Triggers on the original table like "After Insert, After Update, and After Delete Trigger at MySQL level.
CREATE TRIGGER `db`.`car_AFTER_INSERT` AFTER INSERT ON `trn_student_misc_fees_req_status` FOR EACH ROW
BEGIN
# INSERT Query of Another table using 'NEW' Keyword with car table fields.
END
CREATE TRIGGER `db`.`car_AFTER_UPDATE` AFTER UPDATE ON `trn_student_misc_fees_req_status` FOR EACH ROW
BEGIN
# UPDATE Query of Another table using 'NEW' Keyword with car table fields.
END
CREATE TRIGGER `db`.`car_AFTER_DELETE` AFTER DELETE ON `trn_student_misc_fees_req_status` FOR EACH ROW
BEGIN
# DELETE Query of Another table using 'OLD' Keyword with car table fields.
END
read more about trigger Visit https://www.mysqltutorial.org/mysql-triggers.aspx
as #scaisEdge said also create a view from the table and implement that on your spring project.
car_detailed_view.sql [View]
CREATE
ALGORITHM = UNDEFINED
SQL SECURITY DEFINER
VIEW `car_detailed_view` AS
SELECT
car.carId,car.licensePlate,car.carType,car.suv,car.engineCapacity,car.year,car.note,car.status,car.careDate,car.editDate;
FROM
(`car`
INNER JOIN `CarType` ON ((`car`.`car_id` = `CarType`.`car_id`)))
CarDetailedView.java [View Class]
#Immutable
#Entity
#Table(name = "car_detailed_view")
public class CarDetailedView{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long carId;
private String licensePlate;
private int carType;
private boolean suv;
private int engineCapacity;
private int year;
private String note;
private int status;
private LocalDate careDate;
private LocalDate editDate;
//getter,setter and constructor
}

Making primary key out of 2 foreign keys

How do I make a composite primary key out of 2 foreign keys like this?
When I do this in my Account:
#Entity
public class Account {
#Id
private int id;
private String number;
private String IBAN;
private String name;
#OneToMany(mappedBy = "account")
private List<Payment> payments = new ArrayList<>();
public List<Payment> getPayments() {
return payments;
}
public void setPayments(List<Payment> payments) {
this.payments = payments;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getNumber() {
return number;
}
...
And in Payment:
#Entity
#IdClass(AccountPK.class)
public class Payment {
#Id
private int id;
private Timestamp date;
private float amount;
private String currency;
private String detail;
#Id
private int accountId;
#Id
private int counterAccountId;
private int labelId;
#ManyToOne
private Account account;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Timestamp getDate() {
return date;
}
public void setDate(Timestamp date) {
this.date = date;
...
How can I join those?
Assuming the id field is not part of the primary key, remove its #Id annotation. Then annotate the two account fields like this:
#Entity
#IdClass(AccountPK.class)
public class Payment {
private int id;
private Timestamp date;
private float amount;
private String currency;
private String detail;
private int labelId;
#Id
#ManyToOne
private Account account;
#Id
#ManyToOne
private Account counterAccount;
...
Some examples like this are in the JPA 2.2 spec section 2.4.1.

In Spring mvc How to add add set values to mysql

My goal :
In Spring MVC I have to save mobile phone contact list into database.
example:
phone1 sonia 2554654 work
2554654 home
multiple phone_number with multiple phone_Number type
contacts table
id,
contact_name
phone_number
phone_type
in my java class I have
public class ContactMobile {
private String type;
private String number;
public ContactMobile() {
}
public ContactMobile(String type, String number) {
super();
this.type = type;
this.number = number;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
}
and here I use SET for phone number and type
#Entity
#Table(name = "_contact")
public class MobileContact {
private String id;
private String fullname;
private Set<ContactMobile> mobileNumbers;
public MobileContact(String fullname, Set<ContactMobile> mobileNumbers) {
super();
this.fullname = fullname;
this.mobileNumbers = mobileNumbers;
}
#Id
#Column(name = "Id")
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#Column(name = "fullname")
public String getFullname() {
return fullname;
}
public void setFullname(String fullname) {
this.fullname = fullname;
}
public Set<ContactMobile> getMobileNumbers() {
return mobileNumbers;
}
public void setMobileNumbers(Set<ContactMobile> mobileNumbers) {
this.mobileNumbers = mobileNumbers;
}
public MobileContact() {
super();
}
}
I am using hibernate to store data..
my question is in my MobileContact class in
public Set<ContactMobile> getMobileNumbers() {
return mobileNumbers;
}
what annotation I have to use here to save multiple phonenumbers?
The MobileContact entity has many ContactMobile, it is a OneToMany relation. In your ContactMobile table, you should has a field for the id of MobileContact, like mobile_contact_id, and set the join column on that field as below in your ContactMobile:
#OneToMany(fetch = FetchType.LEZY)
#JoinColumn(name = "mobile_contact_id")
private Set<ContactMobile> mobileNumbers;
You can get the detail about the relation in this.
You can use the Embeddables (instead of Entities) for very simple value objects like MobileContact (then they do not need an ID, and the are no just simple value objects without own identity)
#Embeddable
public class ContactMobile {...
//implement an equals and hashcode method!
}
public class MobileContact {
...
#ElementCollection
private Set<ContactMobile> mobileNumbers;
...
}
#See Java Persistence/ElementCollection

JPA Many to Many cascade problem

If I create a Customer and Controller, then associate my Controller with a customer it saves fine.
If I then remove my controller it doesn't remove the relationship between them.
This causes an EntityNotFoundException when I load the Customer.
javax.persistence.EntityNotFoundException: Unable to find Controller with id 22
I'd like to know how to map this so that when a Controller is deleted the relationship is also deleted.
Database Tables
customer
controller
customer_controllers - mapping table.
The Controller's id is not getting removed from the customer_controllers mapping table.
#Entity
public class Customer implements Serializable{
private Integer id;
private Set<Controller> controllers;
#Id
#GeneratedValue
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
#ManyToMany(cascade={CascadeType.ALL})
public Set<Controller> getControllers()
{
return controllers;
}
public void setControllers(Set<Controller> controllers)
{
this.controllers = controllers;
}
}
#Entity
public class Controller implements Serializable{
private Integer id;
private String name;
private String abbreviation;
#Id
#GeneratedValue
public Integer getId()
{
return id;
}
public void setId(Integer id)
{
this.id = id;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getAbbreviation()
{
return abbreviation;
}
public void setAbbreviation(String abbreviation)
{
this.abbreviation = abbreviation;
}
}
If you have a ManyToMany then you should map Controller to Customer with a
#ManyToMany(mappedBy="controllers")
or the other way around, depending on which side is the owning side.
As you have it now the relation is not fully defined and it will fail on events like "Cascade".
Have you checked the javadoc for #ManyToMany?
It includes the above example mappings.
you need to make the relationship bidirectional, so that the controller object is aware of its relationship to the customer. Yhis means that when the controller is deleted the record in the join table is also deleted.
This isn't the exact mapping but it gives you the idea.
#Entity
public class Controller implements Serializable{
private Integer id;
private String name;
private String abbreviation;
private Set<Customer> customers;
#Id
#GeneratedValue
public Integer getId()
{
return id;
}
public void setId(Integer id)
{
this.id = id;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getAbbreviation()
{
return abbreviation;
}
public void setAbbreviation(String abbreviation)
{
this.abbreviation = abbreviation;
}
#ManyToMany(cascade={CascadeType.ALL})
public Set<Customer> getCustomers()
{
return customers;
}
public void setCustomers(Set<Customers> customers)
{
this.customers= customers;
}
}

Categories