Hibernate Field annotation joinColumn set id and get object - java

Is there anyway to set id and get project object for the below project field using filed annotation. so that i can set only project id while persisting in this child table instead of setting the whole object while persisting since we are going to save only id of project in board_project table. My be a duplicate i couldn't find other links. This is like we are in practice of using filed annotation instead of method.
Using : hibernate5.0 - jpa2.1 lombok(i.e getter/setter) for Spring-data-commons-1.13 for CRUD Operations
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table(name = "board_project")
public class BoardProject {
#Id
#SequenceGenerator(name = "board_project_id_generator", sequenceName = "board_project_id_seq", allocationSize = 1)
#GeneratedValue(generator = "board_project_id_generator")
private Long id;
#Column(name = "board_id")
private Long boardId;
#ManyToOne
#JoinColumn(name = "project_id")
private Project project; // field set id and get object
}
Project Entity :
public class Project{
#Id
#SequenceGenerator(name = "project_id_generator", sequenceName = "project_id_seq", allocationSize = 1)
#GeneratedValue(generator = "project_id_generator")
private Long id;
#Column(name = "name")
private String name;
}
Update: Found something like this
#ManyToOne
#JoinColumn(name = "project_id", updatable = false, insertable = false)
private Project project;
#Column(name = "project_id")
#NotNull
private Long projectId;
Don't know is it ok
Any help on this would be great.

Related

Spring JPA: Error when trying to create the foreign key constraints

I am trying to map some columns of a big database with JPA, so i can fetch some data from it.
This database has composite primary keys, and some of these are also foreign keys. Im fairly new to JPA mapping, so i need some help.
Here's the error i get:
org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL "alter table tbpedidoentrega add constraint FKiwjj63py270eqhfb1olp08oox foreign key (fk_cliente) references tbcadastro" via JDBC Statement
and also:
ERROR: number of referencing and referenced columns for foreign key disagree
It would seem that JPA is not specifying the columns that it needs to reference in the end of the command (the correct command would be alter table tbpedidoentrega add constraint FKiwjj63py270eqhfb1olp08oox foreign key (fk_cliente) references tbcadastro (codigo)), specifying just the table. But why?
Here's my code:
The Client class
package com.agilsistemas.construtordepedidos.model;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
#Entity
#Getter
#Setter
#NoArgsConstructor
#Table(name = "tbcadastro")
public class ClienteModel implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "codigo")
int idCliente;
#Column(name = "razao")
String razaoSocial;
#Column(name = "logradouro")
String rua;
#Column(name = "numero")
String numero;
#Column(name = "bairro")
String bairro;
#Column(name = "complemento")
String complemento;
#Column(name = "cidade")
String cidade;
#Column(name = "fixo")
String telefoneFixo;
#Column(name = "celular")
String celular;
#Column(name = "cliente")
String cliente;
}
The Order class:
package com.agilsistemas.construtordepedidos.model;
import java.io.Serializable;
import java.time.LocalDate;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
#Entity
#Getter
#Setter
#NoArgsConstructor
#Table(name = "tbpedidoentrega")
public class PedidoModel implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id_pedido", nullable = false)
#SequenceGenerator(name = "sqpedido")
int idPedido;
#Column(name = "data_pedido", nullable = false)
LocalDate dataPedido;
#Column(name = "hora_pedido", nullable = false)
LocalDate horaPedido;
#ManyToOne
#JoinColumn(name = "fk_funcionario")
FuncionarioModel fkFuncionario;
#ManyToOne
#JoinColumn(name = "fk_cliente")
ClienteModel fkCliente;
#OneToMany(mappedBy = "pedido")
List<ItemPedidoModel> itensPedido;
}
I was expecting this to create the FKs and start the backend. I think the issue lies in the end of the SQL command generated by hibernate (It was supposed to be references tbcadastro (codigo)), but i dont know why it is generating like this.
After some medling and some research, I was able to solve the problem.
The problem was that the table Cliente had a composite primary key, so i needed to implement a special class to specify the composite key:
package com.agilsistemas.construtordepedidos.model;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
#Embeddable
#Getter
#Setter
#EqualsAndHashCode
#AllArgsConstructor
public class IdClienteModel implements Serializable {
#Column(name = "codigo")
private int idCliente;
#ManyToOne
#JoinColumn(name = "empresa")
private EmpresaModel idEmpresa;
}
Then i implemented the ClienteModel class like so:
package com.agilsistemas.construtordepedidos.model;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Table;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
#Entity
#Getter
#Setter
#NoArgsConstructor
#Table(name = "tbcadastro")
public class ClienteModel implements Serializable {
#EmbeddedId
private IdClienteModel idCliente; //using the object as the ID
#Column(name = "razao")
String razaoSocial;
#Column(name = "logradouro")
String rua;
#Column(name = "numero")
String numero;
#Column(name = "bairro")
String bairro;
#Column(name = "complemento")
String complemento;
#Column(name = "cidade")
String cidade;
#Column(name = "fixo")
String telefoneFixo;
#Column(name = "celular")
String celular;
#Column(name = "cliente")
String cliente;
}
And now, in the Pedido (Order) class, i can get the OneToOne relation like this:
#OneToOne
#JoinColumns({
#JoinColumn(name = "fk_cliente", referencedColumnName = "codigo", insertable = false, updatable = false),
#JoinColumn(name = "fk_empresa", referencedColumnName = "empresa", insertable = false, updatable = false) })
ClienteModel fkCliente;
I did this to all the other entities that had composite PKs also, and now the application starts propperly. I hope this awnser can help someone else.

Automatic Column name generation for JPA table mapping

I am trying to map entity tables with #ManyToOne and #OneToMany. The mapping column is in the child table named "internal_plan_id". As per the requirement I can not change the names. Below are the two entity tables:
PARENT TABLE
import java.sql.Timestamp;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
#Entity
#Getter
#Setter
//#Data
#NoArgsConstructor
#Table(name = "financial_plan_details", schema = "financialplanadmin")
public class FinancialPlanDao {
// This internalId is the primary key of the table.
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "internal_plan_id")
private int internalId;
// This stores the plan status into the database table.
#Column(name = "plan_status")
#Size(max = 10)
private String planStatus;
#Column(name = "presentation_file_key")
#Size(max = 500)
private String presentationFileKey;
#Column(name = "create_timestamp")
#NotNull
private Timestamp createdTimestamp;
#OneToMany(mappedBy = "financialPlan")
private List<FinancialSubPlan> subPlans;
}
CHILD TABLE :
#Entity
#Getter
#Setter
#NoArgsConstructor
#Table(name = "financial_plan_subplan", schema = "financialplanadmin")
#JsonInclude(Include.NON_NULL)
public class FinancialSubPlan {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "subplan_id")
private int subPlanId;
#Column(name = "external_subplan_id")
private String externalSubplanId;
#Column(name = "is_chosen")
private Boolean subPlanIsChosen;
#ManyToOne
#JoinColumn(name = "internal_plan_id")
private FinancialPlanDao financialPlan;
}
I am getting the error as :
ERROR: column "internal_plan_id_internal_plan_id" of relation "financial_plan_subplan" does not exist.
The existing column name for mapping in financial_subplan is "internal_plan_id". The above name "internal_plan_id_internal_plan_id" is automatically generated. So is there any way to reduce this to only "internal_plan_id".
The problem was with setting values of the mapped classes. The first thing after forming up the parent class, is to set the parent class into the child class, that is subPlans.set(financialPlan). Then after that we have to set the child class into the parent class, that is financialPlan.set(List of subPlan). I missed the setting up of parent into child.
You can also refer to this JPA / Hibernate One to Many Mapping Example with Spring Boot
In this you can see that after creation of Post object, the Comment object sets the Post object and after that the Post object sets the comment object, before saving it to the database.

How can i add an record by using id reference of other related table?

I've two entities which are named Airport and Route. Route has two field which named startPoint and endPoint. Both of them will be id value of Airport entity. I'm adding two airport entity, after that, I want to add Route by using id values of these airport records. I got an error like that
"message": "JSON parse error: Cannot construct instance of com.finartz.airlines.entity.Airport (although at least one Creator exists): no int/Int-argument constructor/factory method to deserialize from Number value (1); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of com.finartz.airlines.entity.Airport (although at least one Creator exists): no int/Int-argument constructor/factory method to deserialize from Number value (1)\n at [Source: (PushbackInputStream); line: 2, column: 18] (through reference chain: com.finartz.airlines.entity.Route[\"startPoint\"])"
these are my entities:
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.*;
import java.io.Serializable;
import java.time.LocalDateTime;
#Data
#Builder
#Entity
#Table(name = "airport")
#NoArgsConstructor
#AllArgsConstructor
#EntityListeners(AuditingEntityListener.class)
public class Airport implements Serializable {
private static final long serialVersionUID = -3762352455412752835L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "code")
private String code;
#Column(name = "name")
private String name;
#Column(name = "city")
private String city;
#Column(name = "country")
private String country;
#Column(name = "description")
private String description;
#CreationTimestamp
#Column(name = "created_on", nullable = false, updatable = false)
private LocalDateTime createdOn;
#UpdateTimestamp
#Column(name = "updated_on")
private LocalDateTime updatedOn;
}
import io.swagger.annotations.ApiModel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.*;
import java.io.Serializable;
import java.time.LocalDateTime;
#Data
#Builder
#Entity
#Table(name = "route")
#NoArgsConstructor
#AllArgsConstructor
#EntityListeners(AuditingEntityListener.class)
#ApiModel(value = "route")
public class Route implements Serializable {
private static final long serialVersionUID = -8451228328106238822L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "fk_start_point",referencedColumnName = "id")
private Airport startPoint;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "fk_end_point",referencedColumnName = "id")
private Airport endPoint;
#CreationTimestamp
#Column(name = "created_on", nullable = false, updatable = false)
private LocalDateTime createdOn;
#UpdateTimestamp
#Column(name = "updated_on")
private LocalDateTime updatedOn;
}
And repository of the Route is below:
import com.finartz.airlines.entity.Route;
import com.finartz.airlines.repository.RouteRepository;
import com.finartz.airlines.util.HibernateUtil;
import lombok.AllArgsConstructor;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.springframework.stereotype.Repository;
import java.util.List;
#Repository
#AllArgsConstructor
public class RouteRepositoryImpl implements RouteRepository {
public Long add(Route route){
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction tx;
Long routeId;
tx = session.beginTransaction();
routeId = (Long) session.save(route);
tx.commit();
session.close();
return routeId;
}
}
How can I add new Route by using request which provided below?
{
"startPoint":1,
"endPoint":2
}
I would use the session's entity manager to get a reference to an airport from the DB.
Construct using this code whenever you want to create a Route this way:
EntityManagerFactory emf = session.getEntityManagerFactory();
EntityManager em = emf.createEntityManager();
Airport startPoint = em .getReference(Airport.class, startPointID);
Airport endPoint = em .getReference(Airport.class, endPointID);
It should be something like this
session.beginTransaction();
session.save(route);
tx.commit();
Long id = route.getId();
session.close();
return id;
You should not use begin/close transaction. Use Spring Data JPA, it manage transaction session automatically. Your way is not best practices since you use Spring Boot (Let's see https://github.com/donhuvy/library/blob/master/src/main/java/com/example/library/controller/BookController.java#L29 very simple and easy).

Whole table not showing in JSON when doing Hibernate mapping

The table is created successfully and filled with information in H2 database as seen here:
When using Spring boot to display this table information with JSON format i only see this:
Here you can see the code snippet from the object
package com.share.sharelt.entity;
import com.fasterxml.jackson.annotation.JsonBackReference;
import lombok.Data;
import javax.persistence.*;
import java.math.BigDecimal;
import java.util.Date;
#Entity
#Data
#Table(name = "item_rental")
public class ItemRental {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private long id;
#Column(name = "created")
private Date created;
#Column(name = "cost")
BigDecimal cost;
#Column(name = "rent_begin")
private Date rentBegin;
#Column(name = "rent_end")
private Date rentEnd;
#Column(name = "is_confirmed")
private boolean isConfirmed;
#JsonBackReference
#OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name = "renter_id", nullable = true)
private User user;
public ItemRental(){};
}
The problem is that i want to see the whole table information, more specifically the "renter_id" column
One of the solutions is to create a DTO class which is gonna be a JSON wrapper to your ItemRental entity
Something like ItemRentalDTO and UserDTO with all fields of ItemRental and User entity class
Link: https://www.baeldung.com/entity-to-and-from-dto-for-a-java-spring-application

Column still added after using javax.persistence.Transient?

So I have a hibernate model class, which is:
import javax.persistence.Transient;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
#Entity
#Table(name = "transaction_header")
public class TransactionHeader implements java.io.Serializable {
#Column(name = "transaction_header_id", updatable = false, nullable = false, columnDefinition = "serial")
private Long transactionHeaderId;
#Column(name = "trans_type_code")
private String transactionTypeCode;
#Transient
public String stateTax;
#Transient
public String federalTax;
/**then setter getter code**/
}
When I run it on my local database, federal Tax and state Tax column were still generated even I already used Transient on it. I need those 2 columns to not be generated on my database. How can I do it? Thanks

Categories