Hi im trying to do a persist but looks like if one of the atributes never was set but, just before do the persist I print the value and is set. I´m working with postgrest
My persist metod
public void saveText(Document document){
sessionFactory = new Configuration().configure().buildSessionFactory();
Session session = sessionFactory.getCurrentSession();
System.out.println(document.getText());
System.out.println(document.getId());
try {
session.beginTransaction();
session.persist(document);
session.getTransaction().commit();
}
catch (HibernateException e) {
e.printStackTrace();
session.getTransaction().rollback();
}
}
My object to pesist
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
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 br.com.symsar.sysged.acessobd.AccesData;
#Entity
#ManagedBean
#SessionScoped
#Table(name = "documents", schema = "public")
public class Document implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "\"id\"")
private int id;
#Column(name = "\"text\"")
private String text;
public void persist() {
AccesData access = new AccesData();
access.saveText(this);
}
/**
* #return the text
*/
public String getText() {
return text;
}
/**
* #param text
* the text to set
*/
public void setText(String text) {
this.text = text;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
}
Sql query showed by hibernate
Hibernate: insert into public.documents ("id", "text") values (null, ?)
This is the error:
ERROR: ERRO: Null value in the column "id" violates not-null constraint
Field id have JPA annotation #Id in your entity class. It's mean's that it can't be null. Try insert value without id parameter:
Hibernate: insert into public.documents ("text") values (?)
Try removing annotations
#ManagedBean
#SessionScoped
I resolved not using session factory now I´m using entity manager, when I made this change works.
Thanks all for the ideas
Related
i'm not a professional in spring boot / hibernate jpa, so i apologize in advance.
I have 2 Entities, one called Document and the other called Bgo. Document is the parent table and Bgo the child. So my objective is to create the Document and after that, Bgo will receive it's id, for example:
When i create the first Document, it will have id_document = 1, so after that, the Bgo will have id_document = 1 as well.
I want to populate the child's id with the parent's id.
Here is the Parent Entity:
package com.testing.testing.models;
import java.io.Serializable;
import java.sql.Date;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;
#Entity
#Table(name = "DOCUMENT")
public class Document implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id_document;
private int num_document;
private Date date;
#OneToOne(mappedBy = "document", cascade = CascadeType.ALL)
private Bgo bgo;
public Document() {
}
public Document(Bgo bgo) {
this.id_document = bgo.getId_document();
this.bgo = bgo;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public Bgo getBgo() {
return bgo;
}
public void setBgo(Bgo bgo) {
this.bgo = bgo;
}
public long getId_document() {
return id_document;
}
public void setId_document(long id_document) {
this.id_document = id_document;
}
public int getNum_document() {
return num_document;
}
public void setNum_document(int num_document) {
this.num_document = num_document;
}
}
And Child Entity:
package com.testing.testing.models;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.Table;
#Entity
#Table(name = "BGO")
public class Bgo implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private long id_document;
private String name_bgo;
private int num_bgo;
#OneToOne
#PrimaryKeyJoinColumn(name = "id_document", referencedColumnName = "id_document")
private Document document;
public Bgo() {
}
public Bgo(Document document) {
this.id_document = document.getId_document();
this.document = document;
}
public long getId_document() {
return id_document;
}
public void setId_document(long id_document) {
this.id_document = id_document;
}
public String getName_bgo() {
return name_bgo;
}
public void setName_bgo(String name_bgo) {
this.name_bgo = name_bgo;
}
public int getNum_bgo() {
return num_bgo;
}
public void setNum_bgo(int num_bgo) {
this.num_bgo = num_bgo;
}
public Document getDocument() {
return document;
}
public void setDocument(Document document) {
this.document = document;
}
}
I used the term PrimaryKeyJoinColumn cause i want Bgo's id to be the Document's id, thats why i also used the same name "id_document". So Bgo's id will be Primary and Foreign at the same time (if it is wrong please tell me a better way to do it, knowledge is always welcoming)
I have also Document's Repository:
package com.testing.testing.repository;
import com.testing.testing.models.Document;
import org.springframework.data.jpa.repository.JpaRepository;
public interface DocumentRepository extends JpaRepository<Document, Long> {
}
And Bgo's:
package com.testing.testing.repository;
import com.testing.testing.models.Bgo;
import org.springframework.data.jpa.repository.JpaRepository;
public interface BgoRepository extends JpaRepository<Bgo, Long> {
}
Document's Controller:
package com.testing.testing.controllers;
import java.util.List;
import com.testing.testing.models.Document;
import com.testing.testing.repository.DocumentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
#RequestMapping(value="/document")
public class DocumentController {
#Autowired
DocumentRepository documentRepository;
#GetMapping
public List<Document> listDocument() {
return documentRepository.findAll();
}
#PostMapping
public Document createDocument(#RequestBody Document document) {
return documentRepository.save(document);
}
}
Bgo's Controller:
package com.testing.testing.controllers;
import java.util.List;
import com.testing.testing.models.Bgo;
import com.testing.testing.repository.BgoRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
#RequestMapping(value="/bgo")
public class BgoController {
#Autowired
BgoRepository bgoRepository;
#GetMapping
public List<Bgo> listBgo() {
return bgoRepository.findAll();
}
}
So basically, the problem is this:
enter image description here
When i create a new Document and also the Bgo object, Bgo's id is 0, as you can see in the image, the object Bgo has the "id_document = 0 ", shouldn't it be id_document = 1 ?
And when i try to list Bgo, it still shows id_document = 0:
enter image description here
That's how i want the database to be:
enter image description here
As you can see, they are different tables. But Document has the primary key and is the parent, and Bgo is a child cause it is receiving Document's id. As you can see, Bgo's has the Document's id, it is primary and foreign at the same time, thats why i used PrimaryKeyJoinColumn. Both of them have the same id, Document's id equals Bgo's id. So whenever i create a Document and a Bgo at the same time, both of them should have the same id.
you might need to use the inheritance functionality comes with Spring instead. have a look at this:
https://www.baeldung.com/hibernate-inheritance
you can for instance use the #Inheritance(strategy = InheritanceType.SINGLE_TABLE)
on your parent table. and then you will annotate the child with just the #Entity
and then you will extend it as you normally do in a normal Inheritance scenario
so your parent class will look like so:
import java.sql.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.Table;
import javax.persistence.InheritanceType;
#Entity
#Table(name = "Document")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class Document {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "Id")
private Integer Id;
#Column(name = "num_document")
private int num_document;
#Column(name = "date")
private Date date;
public Document() {
}
public Document( int num_document, Date date) {
super();
this.num_document = num_document;
this.date = date;
}
}
and the child will look like so
import java.sql.Date;
import javax.persistence.Entity;
import javax.persistence.Table;
#Entity
#Table(name = "Bgo")
public class Bgo extends Document {
#Column(name = "name_bgo")
private String name_bgo;
#Column(name = "num_bgo")
private int num_bgo;
public Bgo(String name_bgo, int num_bgo) {
super();
this.name_bgo = name_bgo;
this.num_bgo = num_bgo;
}
public Bgo() {
super();
}
}
and you will have One JPARepository which looks like so;
import org.springframework.data.jpa.repository.JpaRepository;
public interface DocumentRepository extends JpaRepository<Document, Integer> {
}
the result of this code, will generate one table in your database with one extra column dtype which will identify the record to be either Bgo or any other type you might need to add in the future. this is the idea behind inheritance anyway
I hope this helped
Here are the three different inheritance strategy you have using spring
Single mapping is the default mapping
And it uses #inheritance(strategy = InheritanceType.SINGLE_TABLE) annotation to the parent class
In this strategy, the parent class is a table and all its children will be specified in a discriminator column in the parent table. The column called dtype and it contain the name of the entity as a value.
Table per the class strategy is similar to the superclass strategy but the superclass is also an entity you need to avoid this one if you want to make so many join queries
Joined table strategy is used the same as above. In this strategy, the subclasses and the superclass will all be tables in the database, but the subclasses will not inherit the filed of the superclass, it is useful if we want to apply data integrity and null constrains on some field
for more details look here
https://thorben-janssen.com/complete-guide-inheritance-strategies-jpa-hibernate/
choose which one will suit your case and then you can use the implementation I provided in the first answer and you only need to change the this annotation
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
I tried many time to insert id value in my table using below code, but it always throwing org.hibernate.id.IdentifierGenerationException: ids for this class must be manually assigned before calling save(): com.app.entites.LDetails
following is the code in entity class
#Column(name="LID")
#GenericGenerator(name="generatedId", strategy="com.app.common.IdGenerator")
#GeneratedValue(generator="generatedId", strategy=GenerationType.SEQUENCE)
#NotNull
private String lId;
i have implemented id generator using IdentifierGenerator as below
public class IdGenerator implements IdentifierGenerator{
private static String id;
#Override
public Serializable generate(SharedSessionContractImplementor session, Object object) throws HibernateException {
Connection con = session.connection();
try {
Statement statement = con.createStatement();
ResultSet rs = statement.executeQuery("select count(ID) from L_DETAILS");
if(rs.next()) {
int i = rs.getInt(1)+1;
this.id="ll"+i;
System.out.println("generated id is "+id);
return "l"+i;
}
}catch(SQLException e) {
e.printStackTrace();
}
return null;
}
}
Use the following approach for Auto-Id generation of Primary key in your entity class :-
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Entity;
#Entity
#Table(name = "your_table_name")
public class YourEntityClass{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private long id;
//other column names
// setter & getter methods
}
After this, whenever you're saving a new record in your table you don't have to generate a new id
You have forgotten to add the #Id annotation on top. The fact you have added the #GeneratedValue annotation does not mean you can spare the #Id annotation. You still need it.
First let's say we have two tables. One table is an Employee table with the following columns:
EMPLOYEE:
------------------------
emp_id (int, primary key)
emp_name (varchar(125))
emp_dept (foreign key)
emp_intro (text)
The other table is a Department table with the following columns:
DEPARTMENT:
-----------
dept_id (int, primary key)
dept_label (varchar(25))
Here is a sample of the table's values
DEPARTMENT:
------------------------
dept_id | dept_label
------------------------
1 | Sales
------------------------
2 | Technology
------------------------
3 | Finance
In order to return the employee's info with a status label, we need to either perform a JOIN:
SELECT e, d.dept_label FROM employees JOIN department d ON d.dept_id = e.emp_dept
or a multi-table select:
SELECT e.emp_id, e.emp_name, d.dept_label, e.emp_intro FROM employees e, department d WHERE e.emp_dept = d.dept_id
However, when using JPA/Hibernate, we need to create two classes:
Employee.java
package com.example.entities;
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;
#Entity
#Table(name = "employees")
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "emp_id")
private long emp_id;
#Column(name = "emp_name")
private String emp_name;
#Column(name = "emp_dept")
private Integer emp_dept;
#Column(name = "emp_intro")
private String emp_intro;
public long getEmp_id() {
return emp_id;
}
public void setEmp_id(long emp_id) {
this.emp_id = emp_id;
}
public String getEmp_name() {
return emp_name;
}
public void setEmp_name(String emp_name) {
this.emp_name = emp_name;
}
public Integer getEmp_dept() {
return emp_dept;
}
public void setEmp_dept(Integer emp_dept) {
this.emp_dept = emp_dept;
}
public String getEmp_intro() {
return emp_intro;
}
public void setEmp_intro(String emp_intro) {
this.emp_intro = emp_intro;
}
public static long getSerialversionuid() {
return serialVersionUID;
}
}
Department.java
package com.example.entities;
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;
#Entity
#Table(name = "departments")
public class Department implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "dept_id")
private long dept_id;
#Column(name = "dept_label")
private String dept_label;
public long getDept_id() {
return dept_id;
}
public void setDept_id(long dept_id) {
this.dept_id = dept_id;
}
public String getDept_label() {
return dept_label;
}
public void setDept_label(String dept_label) {
this.dept_label = dept_label;
}
public static long getSerialversionuid() {
return serialVersionUID;
}
}
Then, there is the repository (DAO):
EmployeeRepository
package com.example.repository;
import.java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import com.example.entities.Employee;
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
#Query("select e, d.dept_label FROM Employee e JOIN Department d ON "
+ "d.dept_id = e.emp_id")
public List<Employee> return getEmployees();
}
and lastly, the Java controller that binds the classed query to an endpoint of the application:
EmployeeController.java
package com.example.controllers;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.example.entities.Department;
import com.example.entities.Employee;
import com.example.repository.EmployeeRepository;
#Controller
public class EmployeeController {
#Autowired
EmployeeRepository er;
#RequestMapping(value = "/getEmployees")
public #ResponseBody List<Employee> getEmployees() {
return er.getEmployees();
}
}
I have already tested this entire structure with only retrieving rows inside of the Employee table (i.e. #Query("SELECT e FROM Employee e") ) and everything returns as is.
MY MAIN ISSUE is how does one return a JOIN QUERY while the query is inside of a specific class (table), being Employee, if I require contents inside of Department?
I've already tried #JoinColumn annotations and that didn't work as well (perhaps I did it wrong).
Any ideas? Thanks.
You dont have to use raw joins to do that, just use proper relation mapping. Relation between Employee and Departament sounds like #ManyToOne or #ManyToMany.
You will be able to eg employee.getDepartament() or query by employee.departament.name=:name
http://www.objectdb.com/api/java/jpa/ManyToMany
You can even map bidirectional relations so you will be able to get deparament from employee, as well as all employees from given deparaments
PS. #JoinColumn is used to delare DB columnt used for joins it it is different then created by selected named strategies (usualy entityname_id). Actual relation mapping is done by declaring #OneToOne #OneToMany #ManyToMany and those can but doesn't have to be used with #JoinColumn. It is strict JPA question.
Here you have complete documentation of JPA 2.1 specification
It describes in details how to declare relations as well as #MappedSuperclass, inheritance strategies and all other usefull stuff.
I have a class that uses a Hibernate session to call a stored procedure via a JPA #NamedNativeQuery using an in memory H2 database for testing (the actual database is MySQL). The stored procedure inserts a record into a database table and then returns that row.
However during testing, on converting to the JPA #Entity, I am seeing an H2 database error: org.h2.jdbc.JdbcSQLException: Column "Id" not found.
I've documented a cut down version of the code below.
As far as I can tell I think it has something to do with the H2 interpretation of the #Id annotation, but don't understand why, so any help would be gratefully appreciated...
NB - I have searched Stack overflow fairly extensively, including the issue relating to the use of double quotes for column specification, but don't think that this relates to my situation...
Table
CREATE TABLE History.Status_Report (
Id INT NOT NULL AUTO_INCREMENT,
Unique_Users INT NOT NULL,
PRIMARY KEY (Id)
);
Stored Procedure
CREATE PROCEDURE History.Status_Reporting(reporting_date DATE)
BEGIN
INSERT INTO history.status_report (Unique_Users) VALUES (10);
SELECT *
FROM History.Status_Report WHERE Id = LAST_INSERT_ID();
END;
Entity
package com.test;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.NamedNativeQuery;
import javax.persistence.Table;
import java.io.Serializable;
#NamedNativeQuery(name = "callStatusReporting", query = "CALL Status_Reporting(:reporting_date)", resultClass = StatusReportEntity.class)
#Entity
#Table(name = "Status_Report", catalog = "History")
public class StatusReportEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
#Column(name = "Id")
protected Integer id;
#Column(name = "Unique_Users")
protected int uniqueUsers;
public Integer getId() {
return this.id;
}
public int getUniqueUsers() {
return this.uniqueUsers;
}
}
Class under test
package com.test;
import org.hibernate.Query;
import org.hibernate.Session;
public class MyListener {
public StatusReportEntity doRequest(Date reportDate) {
Session session = HibernateUtil.openSession(); // returns a MySQL session or H2 if testing…
try {
Query query = session.getNamedQuery("callStatusReporting").setParameter("reporting_date", reportDate);;
StatusReportEntity statusReportEntity = (StatusReportEntity) query.uniqueResult();
return statusReportEntity;
} catch (Exception e) {
System.err.println(e);
} finally {
session.close();
return null;
}
}
H2 Aliases
To enable testing using H2, There is also a file to specify the necessary aliases:
CREATE SCHEMA IF NOT EXISTS History;
CREATE ALIAS IF NOT EXISTS Status_Reporting FOR "com.test.StoredProcs.statusReporting";
Test Class to be used by Alias
And a test class to return a default result from the SP call:
package com.test;
import com.test.StatusReportEntity;
public class StoredProcs {
public static StatusReportEntity statusReporting(Date reportingDate) {
StatusReportEntity statusReportEntity = StatusReportEntity.builder().withId(1).withUniqueUsers(10).build();
return statusReportEntity;
}
}
Test Class
package com.test;
import com.test.MyListener;
import java.util.Calendar;
import org.junit.Test;
import static org.junit.Assert.*;
public class MyListenerTest {
private MyListener listener;
#Test
public void listenerReturnsLatestData() throws Exception {
MyListener myListener = new MyListener();
assertNotNull(myListener.statusReporting(Calendar.getInstance().getTime()));
}
}
CREATE TABLE PERSON(
PERSON_ID IDENTITY PRIMARY KEY,
GIVEN_NAME VARCHAR(20),
FIRST_NAME VARCHAR(20),MIDDLE_NAME VARCHAR(20),
LAST_NAME VARCHAR(20),TITLE VARCHAR(20),NAME_SUFFIX VARCHAR(20));
The entity class must use any Generation strategy.
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name ="PERSON_ID")
private int personId;
Hello brothers and sisters,
I have a class that keeps userAuthInformatin with authuserid column,username column, and authusertoken column.
I want to insert uuid number in authusertoken column with every insert. I learned about Generated(GenerationTime.INSERT) but i don't know exact way to do this.
package entities;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.Generated;
import org.hibernate.annotations.GenerationTime;
#Entity
#Table(name = "authusers")
public class AuthUser {
#Id
#GeneratedValue
private int authuserid;
#Generated(GenerationTime.INSERT)
#Column(name = "authusertoken")
private long authusertoken;
#Column(name = "username")
private String username;
public int getAuthuserid() {
return authuserid;
}
public void setAuthuserid(int authuserid) {
this.authuserid = authuserid;
}
public long getAuthusertoken() {
return authusertoken;
}
public void setAuthusertoken(long authusertoken) {
this.authusertoken = authusertoken;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
You can simply use the UUID Java class and assign a value to this token field at object creation time:
#Column(name = "authusertoken", columnDefinition = "BINARY(16)")
private UUID authusertoken = UUID.randomUUID();
If the current associated row already has a value, when fetching the Entity, Hibernate will set it using Reflection and override the authusertoken with the row's column value.
If this is a new object, the authusertoken will get a default UUID when the object is instantiated.