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.
Related
I am trying to write a query that retrieves the first_value, i.e., the max of a column in JPA + Spring Boot.
The problem is that the DB query works, but the JPA query doesn't.
It has something to do with the fact that the field I am trying to retrieve is part of a Composite Embedded Primary Key.
I am getting the error Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token: over near line 1, column 32 [select first_value(snapshotId) over (order by id.snapshotId desc) AS snapshotId from xyz.model.ValuesEntity]
May I request you SMEs out there to help me? I'll be very grateful
package xyz.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Index;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.MapsId;
import javax.persistence.Table;
import java.io.Serializable;
import java.time.ZonedDateTime;
import java.util.Objects;
import java.util.UUID;
#Entity
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Builder
#ToString(onlyExplicitlyIncluded = true)
#Table(name = "values", indexes = {
#Index(name = "values_scheduled_at_index", columnList = "scheduled_at")
})
public class ValuesEntity {
#ToString.Include
#Column(name = "instance", length = 18)
private String instance;
#EmbeddedId
#ToString.Include
private ValuesPrimaryKey id;
#MapsId("valuePermId")
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "value_perm_id")
private ValuePermsEntity valuePermsEntity;
#ToString.Include
#Column(name = "enabled")
private boolean enabled;
#ToString.Include
#Column(name = "scheduled_at", nullable = false)
private ZonedDateTime scheduledAt;
#Getter
#Builder
#Embeddable
#NoArgsConstructor
#AllArgsConstructor
#ToString(onlyExplicitlyIncluded = true)
public static class ValuesPrimaryKey implements Serializable {
private static final long serialVersionUID = -10L;
#ToString.Include
#Column(name = "value_id", length = 18, nullable = false)
private String valueId;
#ToString.Include
#Column(name = "value_perm_id", nullable = false)
private UUID valuesPermId;
#ToString.Include
#Column(name = "snapshot_id", nullable = false)
private Integer snapshotId;
}
}
package xyz.repository;
import xyz.model.ValuesEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import java.time.ZonedDateTime;
public interface ValuesRepository extends JpaRepository<ValuesEntity, ValuesEntity.ValuesPrimaryKey> {
#Query("select first_value(snapshotId) over (order by id.snapshotId desc) AS snapshotId from ValuesEntity")
Integer findFirstMaxSnapshotId();
}
I am defining a class User which is a parent to my two other classes: Submitter and Assignee. User has all my attributes listed and Submitter and Assignee will just inherit all its attributes. A submitter can submit many Requests.
The models I have coded look like this:
User
package com.merck.trackertest.models;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table;
import lombok.Data;
import lombok.NoArgsConstructor;
#Entity
#Data
#NoArgsConstructor
#Table(name = "users")
#Inheritance(strategy = InheritanceType.JOINED)
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String firstName;
private String lastName;
private String isid;
private String email;
public User(String firstName, String lastName, String isid, String email) {
this.firstName = firstName;
this.lastName = lastName;
this.isid = isid;
this.email = email;
}
}
Submitter
package com.merck.trackertest.models;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
#Entity
#Data
#NoArgsConstructor
#EqualsAndHashCode(callSuper = true)
public class Submitter extends User {
#OneToMany(
cascade = CascadeType.ALL,
orphanRemoval = true
)
#JoinColumn(
name = "submitter_id",
referencedColumnName = "id"
)
private List<Request> requests = new ArrayList<>();
public Submitter(String firstName, String lastName, String isid, String email) {
super(firstName, lastName, isid, email);
}
public void addToList(Request request) {
requests.add(request);
}
public void deleteFromList(Request request) {
requests.remove(request);
}
}
Request
package com.merck.trackertest.models;
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.Table;
import lombok.Data;
import lombok.NoArgsConstructor;
#Entity
#Data
#NoArgsConstructor
#Table(name = "requests")
public class Request {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String receivedDate;
private String startDate;
private String endDate;
private String requestNumber;
#ManyToOne
#JoinColumn(name = "submitter_id", referencedColumnName = "id")
private Submitter submitter;
private String assigneeId;
private String status;
public Request(String receivedDate, String startDate, String requestNumber, String status) {
this.receivedDate = receivedDate;
this.startDate = startDate;
this.requestNumber = requestNumber;
this.status = status;
}
}
I have not modelled the Assignee table as of yet.
My concern is the table Submitter does not show anything but the id, is there a way to present the data with the id to the list of requests. Would using #Embeddable and #Embedded make the most sense here, can I do that even though I have defined Request as an Entity. What is the correct way of referencing a OneToMany Bidirectional relationship which uses Inheritance.
Table looks like the below which doesn't provide any useful information.
If you want the Submitter and Assignee tables created with all the cloumns from the user class, you have 2 choices
Mapped super class :
You need make the user class mapped super class by adding the #MappedSuperClass annotation and removing the #Entity and #Table annotations.
Classes having the #MappedSuperClass annotation won't be persisted in the database (no table created).
Entities extending this MappedSuperClass will inherit its properties.
In the database, this will correspond to one Sumbitter table with columns for the declared and inherited fields of the User class.
Table per class strategy :
The Table per Class strategy maps each entity to its table, which contains all the properties of the entity, including the ones inherited.
For this you need to modify the inheritance strategy annotation :
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
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.
I'm using hibernate to mapping and class but i getting and error. I my mapping is one student has many school subjects. I make the database first i'm using postgres. Thanks!
CREATE TABLE aluno
(
idAluno serial,
datanascimento date,
matricula character varying(255),
nome character varying(255),
CONSTRAINT pkAluno PRIMARY KEY (idAluno)
);
CREATE TABLE materiaaluno
(
idCurso serial,
nome character varying(255),
idAluno integer NOT NULL,
CONSTRAINT pkMateriAluno PRIMARY KEY (idcurso),
CONSTRAINT fkAluno FOREIGN KEY(idAluno) REFERENCES aluno(idAluno)
);
Warning: #{alunoBean.salvar()}: java.lang.Exception: could not get a field value by reflection getter of modelo.Materia.idcurso
javax.faces.FacesException: #{alunoBean.salvar()}: java.lang.Exception: could not get a field value by reflection getter of modelo.Materia.idcurso
Aluno class
package modelo;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
#Entity
#Table(name = "aluno")
public class Aluno implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "idaluno")
private Integer idaluno;
#Column(name = "nome")
private String nome;
#Temporal(TemporalType.DATE)
#Column(name = "datanascimento")
private Date datanascimento;
#Column(name = "matricula")
private String matricula;
#OneToMany(mappedBy = "aluno", cascade = CascadeType.ALL)
private List<Materia> materias;
// contructors, getters and setters
}
Materia class
package modelo;
import java.io.Serializable;
import java.util.Objects;
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.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
#Entity
#Table(name = "materiaaluno")
public class Materia implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "idcurso")
private Integer idcurso;
#Column(name = "nome")
private String nome;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "idaluno")
private Aluno aluno;
// constructor, getters and setters
}
You probably forgot/miswrote the setters and getters in the entity Materia.
Hibernate tries to access the fields by reflection when it can't do otherwise.
Check the field idcurso
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.