How to autoincrement an Id in a composite primary key in Hibernate? - java

I have a table with a composite primary key - groupId and batchId. Entity class looks like:
#Entity(name="EMPLOYEE")
public class Employee {
#EmbeddedId
private EmployeePK employeePK;
//Other columns and their getters and setters
//Getters and setters
}
Composite PK:
#Embeddable
public class EmployeePK implements Serializable {
private long groupId;
private long batchId;
#GeneratedValue(strategy=GenerationType.AUTO)
public long getBatchId() {
return batchId;
}
public void setBatchId(long batchId) {
this.batchId = batchId;
}
}
I'm trying to auto increment the batch Id, for a new record to be inserted.
//For saving
Employee employee = new Employee();
EmployeePK pk = new IRAmendmentBatchesPK();
pk.setBatchId(0);
pk.setGroupId(4388);
Employee employee = employeeRepository.save(employee);
//Repository Interface
public interface EmployeeRepository extends JpaRepository<Employee, EmployeePK>{
}
I'm explicity setting batchId as 0, in hopes that the auto-incremented value is set in the batchId during save(insert). As of now, this code will save a new entry with batchId as 0.

As I have mentioned in comment, I have used #IdClass it worked while I have tried in hsqldb in-memory database, but failed to work in mysql.
Please note I am using hibernate 5
You may give a try with oracle, I couldn't recollect but it should work. But please check for if any drawbacks with the approach if any.
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.techdisqus</groupId>
<artifactId>spring5-mvc-hibernate-example</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<failOnMissingWebXml>false</failOnMissingWebXml>
<spring.version>5.0.0.RELEASE</spring.version>
<hibernate.version>5.2.11.Final</hibernate.version>
<hibernate.validator>5.4.1.Final</hibernate.validator>
<c3p0.version>0.9.5.2</c3p0.version>
<jstl.version>1.2.1</jstl.version>
<tld.version>1.1.2</tld.version>
<servlets.version>3.1.0</servlets.version>
<jsp.version>2.3.1</jsp.version>
<hsqldb.version>1.8.0.10</hsqldb.version>
</properties>
<dependencies>
<!-- Spring MVC Dependency -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- Spring ORM -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- Hibernate ORM -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
<!-- Hibernate-C3P0 Integration -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-c3p0</artifactId>
<version>${hibernate.version}</version>
</dependency>
<!-- c3p0 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>${c3p0.version}</version>
</dependency>
<!-- Hibernate Validator -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>${hibernate.validator}</version>
</dependency>
<!-- JSTL Dependency -->
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>javax.servlet.jsp.jstl-api</artifactId>
<version>${jstl.version}</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>${tld.version}</version>
</dependency>
<!-- Servlet Dependency -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${servlets.version}</version>
<scope>provided</scope>
</dependency>
<!-- JSP Dependency -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>${jsp.version}</version>
<scope>provided</scope>
</dependency>
<!-- HSQL Dependency -->
<dependency>
<groupId>hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>${hsqldb.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.12</version>
</dependency>
</dependencies>
<build>
<sourceDirectory>src/main/java</sourceDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<!-- Embedded Apache Tomcat required for testing war -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>
</project>
Book.java
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.Table;
#Entity(name = "Book")
#Table(name = "book")
#IdClass( PK.class )
public class Book {
#Id
#Column(name = "registration_number")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long registrationNumber;
#Id
#Column(name = "publisher_id")
private Integer publisherId;
private String title;
public Long getRegistrationNumber() {
return registrationNumber;
}
public void setRegistrationNumber(Long registrationNumber) {
this.registrationNumber = registrationNumber;
}
public Integer getPublisherId() {
return publisherId;
}
public void setPublisherId(Integer publisherId) {
this.publisherId = publisherId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
#Override
public String toString() {
return "Book [registrationNumber=" + registrationNumber + ", publisherId=" + publisherId + ", title=" + title
+ "]";
}
}
PK.java
import java.io.Serializable;
import java.util.Objects;
public class PK implements Serializable {
/**
*
*/
private static final long serialVersionUID = 2371758145387850080L;
private Long registrationNumber;
private Integer publisherId;
public PK(Long registrationNumber, Integer publisherId) {
this.registrationNumber = registrationNumber;
this.publisherId = publisherId;
}
public PK() {
}
#Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
PK pk = (PK) o;
return Objects.equals( registrationNumber, pk.registrationNumber ) &&
Objects.equals( publisherId, pk.publisherId );
}
#Override
public int hashCode() {
return Objects.hash( registrationNumber, publisherId );
}
}
hibernate.cfg.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.archive.autodetection">class,hbm</property>
<property name="hibernate.dialect">org.hibernate.dialect.HSQLDialect</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.connection.driver_class">org.hsqldb.jdbcDriver</property>
<property name="hibernate.connection.username">sa</property>
<property name="hibernate.connection.password"></property>
<property name="hibernate.connection.url">jdbc:hsqldb:mem:test</property>
<property name="hibernate.hbm2ddl.auto">create</property>
<property name="hibernate.c3p0.min_size">5</property>
<property name="hibernate.c3p0.max_size">20</property>
<property name="hibernate.c3p0.acquire_increment">2</property>
<property name="hibernate.c3p0.acquire_increment">1800</property>
<property name="hibernate.c3p0.max_statements">150</property>
</session-factory>
</hibernate-configuration>
HibernateConfig.java
#Configuration
#EnableTransactionManagement
#ComponentScans(value = { #ComponentScan("com.techdisqus")})
public class HibernateConfig {
#Autowired
private ApplicationContext context;
#Bean
public LocalSessionFactoryBean getSessionFactory() {
LocalSessionFactoryBean factoryBean = new LocalSessionFactoryBean();
factoryBean.setConfigLocation(context.getResource("classpath:hibernate.cfg.xml"));
factoryBean.setAnnotatedClasses(Book.class);
return factoryBean;
}
#Bean
public HibernateTransactionManager getTransactionManager() {
HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(getSessionFactory().getObject());
return transactionManager;
}
}
BookDAOImpl.java
#Repository
public class BookDAOImpl implements BookDAO {
#Autowired
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public void save(Book book) {
Session session = this.sessionFactory.openSession();
Transaction tx = session.beginTransaction();
session.persist(book);
tx.commit();
session.close();
}
}
client code:
public class SpringHibernateMain2 {
public static void main(String[] args) {
ApplicationContext appContext = new AnnotationConfigApplicationContext(HibernateConfig.class);
BookDAO personDAO = appContext.getBean(BookDAO.class);
Book book = new Book();
book.setPublisherId(12);
book.setTitle("t 1");
//book.setRegistrationNumber(2l);
personDAO.save(book);
System.out.println("book::"+book);
//context.close();
}
}
from logs while using with H:
Hibernate: call next value for hibernate_sequence Hibernate: insert
into book (title, publisher_id, registration_number) values (?, ?, ?)
book::Book [registrationNumber=1, publisherId=12, title=t 1]
The below is the error I get while I try with MySql
Hibernate: select next_val as id_val from hibernate_sequence for
update Dec 04, 2018 6:24:53 PM
org.hibernate.id.enhanced.TableStructure$1$1 execute ERROR: could not
read a hi value java.sql.SQLSyntaxErrorException: Table
'security.hibernate_sequence' doesn't exist
I have tried with accepted answer in the post
Hibernate insert failing when embedded key contains identity column on SQL Server
but no luck with it.

#Embeddable
public class EmployeePK implements Serializable {
private long groupId;
#GeneratedValue(strategy = GenerationType.AUTO)
private long batchId;
public long getBatchId() {
return batchId;
}
public void setBatchId(long batchId) {
this.batchId = batchId;
}
//implements equals and hashcode
}

It's precised in the Javadoc of oracle that is not possible and not in the spec : https://docs.oracle.com/javaee/6/api/javax/persistence/GeneratedValue.html
Use of the GeneratedValue annotation is not supported for derived primary keys.
And I found nothing about how to do it with build in tools. So you need to do yours own implementation of that.

Related

Cannot pass object to database;detached entity passed to persist

I'm new in jpa and hibernate, and it took me a while to set up the xml file(it might not be whole), lower the errors, and try to figure it all out. I'm using mariadb and have a database called jpadb, which im trying create and pass an "Employee" object from java. I get the error
:org.hibernate.PersistentObjectException: detached entity passed to
persist: model.Employee
my code is as follows:
persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="sample" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<class>model.Employee</class>
<properties>
<property name="javax.persistence.jdbc.driver" value="org.mariadb.jdbc.Driver" />
<property name="javax.persistence.jdbc.url" value="jdbc:mariadb://localhost:3306/jpadb" />
<property name="javax.persistence.jdbc.user" value="root" />
<property name="javax.persistence.jdbc.password" value="root" />
</properties>
</persistence-unit>
</persistence>
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>sqlDemo</groupId>
<artifactId>demo</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>loader.MainApp</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
<version>2.2.3</version>
</dependency>
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
<version>1.0.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.17.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-c3p0</artifactId>
<version>5.2.17.Final</version>
</dependency>
</dependencies>
</project>
Employee.java
package model;
import javax.persistence.*;
#Entity
#Table (name="user")
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private int eid;
#Column(name = "ename")
private String ename;
#Column(name = "salary")
private double salary;
#Column(name = "deg")
private String deg;
public Employee(int eid, String ename, double salary, String deg) {
super( );
this.eid = eid;
this.ename = ename;
this.salary = salary;
this.deg = deg;
}
public Employee( ) {
super();
}
public int getEid( ) {
return eid;
}
public void setEid(int eid) {
this.eid = eid;
}
public String getEname( ) {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public double getSalary( ) {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public String getDeg( ) {
return deg;
}
public void setDeg(String deg) {
this.deg = deg;
}
#Override
public String toString() {
return "Employee [eid=" + eid + ", ename=" + ename + ", salary=" + salary + ", deg=" + deg + "]";
}
}
CreateEmployee.java
package service;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import model.Employee;
public class CreateEmployee {
public static void main( String[ ] args ) {
EntityManagerFactory emfactory = Persistence.createEntityManagerFactory( "sample" );
EntityManager entitymanager = emfactory.createEntityManager( );
entitymanager.getTransaction( ).begin( );
Employee employee = new Employee( );
employee.setEid( 1201 );
employee.setEname( "Maria" );
employee.setSalary( 40000 );
employee.setDeg( "Technical Manager" );
entitymanager.persist( employee );
entitymanager.getTransaction( ).commit( );
entitymanager.close( );
emfactory.close( );
}
}
I'm trying to go through tutorials, but due to hibernate-property version mismatches I'm having a really hard time. It took me a while to find the properties for mariadb in order for this to work. Thanks in advance.
set #GeneratedValue(strategy=GenerationType.IDENTITY) and remove the line employee.setEid( 1201 );
Your id is auto generated, you don't have to pass it when inserting a new row.
Remove the line employee.setEid( 1201 ); and it should do it. You should take a look at entity lifecycle. https://www.javabullets.com/jpa-entity-lifecycle/

How to mapping subquery in select with jpa

I am using spring ,jpa, hibernate,mysql , java 8,.In Dao (which is inteface and extends JpaRepository)
MyTable class
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Transient;
#Entity
#Table(name = "MY_TABLE")
public class MyTable {
#Id
#Column(name = "ID")
private long id;
#Column(name = "ITEM_NAME")
private String itemName;
#Column(name = "ITEM_PRICE")
private int itemPrice;
#Transient
private int col1;
public MyTable() {
}
public MyTable(long id, String itemName, int itemPrice, int col1) {
super();
this.id = id;
this.itemName = itemName;
this.itemPrice = itemPrice;
this.col1 = col1;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getItemName() {
return itemName;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
public int getItemPrice() {
return itemPrice;
}
public void setItemPrice(int itemPrice) {
this.itemPrice = itemPrice;
}
public int getCol1() {
return col1;
}
public void setCol1(int col1) {
this.col1 = col1;
}
}
MyTableDao
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import com.kolip.devchain.model.MyTable;
public interface MyTableDao extends JpaRepository<MyTable , Long> {
#Query(value = "SELECT mt.*, (select count(1) from anotherTable ) as col1 from MY_TABLE mt",nativeQuery = true)
List<MyTable> getMyTableList();
}
pom
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- <dependency> -->
<!-- <groupId>org.springframework.boot</groupId> -->
<!-- <artifactId>spring-boot-starter-security</artifactId> -->
<!-- </dependency> -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
</dependency>
<dependency>
<groupId>com.github.stefanbirkner</groupId>
<artifactId>system-rules</artifactId>
<version>1.16.0</version>
</dependency>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-hibernate5</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
MY_TABLE
CREATE TABLE `my_table` (
`ID` bigint(20) NOT NULL,
`ITEM_NAME` varchar(255) DEFAULT NULL,
`ITEM_PRICE` int(11) DEFAULT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
I try to simplify my problem.I try to get col1 value but i can't find out how should be col1 attribute in entity. Other values can be gotten in entity.
If i use col1 attribute without #Transient , it will work , but col1 is not persistant(Also findAll() not working because there isn't col1 column on db). What should i do ?
you have many options but you could try this the following steps if you are using JPA 2.1:
1) Create a suitable DTO which should include properties that will take the results of your query:
"SELECT mt.*, (select count(1) from anotherTable ) as col1 from MY_TABLE mt"
2) In the MyTable entity, map the native query to your DTO using the #SqlResultSetMapping and #ConstructorResult annotations (a simple search on google will give you lots of usefull info on its usage).(See http://docs.oracle.com/javaee/7/api/javax/persistence/SqlResultSetMapping.html)
3) Modify the MyTableDao to use the native query you created in step 2.
I hope this helps. Goodluck :)

Spring Boot + Hibernate + Postgres - not creating tables

I am trying to generate schema tables based on entities. The application starts correctly, the SQL is generated but there is no result - none of tables are created. What's wrong? I have used the same settings in plain Spring MVC + Hibernate JPA without Spring Boot and everything was working correctly.
Here is my pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.agileplayers</groupId>
<artifactId>applicationname</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>ApplicationName</name>
<description>Application Name</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<!--<scope>runtime</scope>-->
<version>9.4-1201-jdbc41</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.properties:
spring.datasource.url = jdbc:postgresql://localhost:5432/postgres
spring.datasource.driverClassName = org.postgresql.Driver
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQL82Dialect
spring.datasource.schema=schemaName
spring.datasource.username=userName
spring.datasource.password=userPassword
spring.jpa.hibernate.ddl-auto=create
spring.jpa.show-sql=true
spring.jpa.generate-ddl=true
BaseEntity.java:
package com.agileplayers.applicationname.core.domain;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import java.util.Date;
#MappedSuperclass
public class BaseEntity {
#Id
#GeneratedValue
private int id;
private Date createdOn;
public String description;
public BaseEntity() {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Date getCreatedOn() {
return createdOn;
}
public void setCreatedOn(Date createdOn) {
this.createdOn = createdOn;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
example of Entity which extends BaseEntity - Entry.java:
package com.agileplayers.applicationname.core.domain;
import javax.persistence.Entity;
import javax.persistence.ManyToOne;
import java.util.Date;
#Entity
public class Entry extends BaseEntity{
private String type;
#ManyToOne
private Account account;
public Entry() {
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Account getAccount() {
return account;
}
public void setAccount(Account account) {
this.account = account;
}
}
I have fixed the issue. Instead of spring.datasource.schema=schemaName there should be spring.jpa.properties.hibernate.default_schema=schemaName.
The set of necessary properties required for generating tables in my case is the following:
spring.datasource.url = jdbc:postgresql://localhost:5432/postgres
spring.jpa.properties.hibernate.default_schema = schemaName
spring.datasource.username = userName
spring.datasource.password = userPassword
spring.jpa.hibernate.ddl-auto = create-drop
spring.jpa.show-sql = true

Java JPA - No Persistence provider for EntityManager named

Utilising the Java JPA with Eclipse Link I am attempting to persist a simple Post model of a Blog application into a MySQL database however I am recieving the error No Persistence provider for EntityManager named
Here is the code I am utilising
Exception Text
javax.persistence.PersistenceException: No Persistence provider for
EntityManager named blog
javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:85)
javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:54)
com.uk.jacob.blog.controllers.PostController.(PostController.java:9)
com.uk.jacob.blog.controllers.HomeController.doGet(HomeController.java:51)
javax.servlet.http.HttpServlet.service(HttpServlet.java:620)
javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
App Structure
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.uk.jacob</groupId>
<artifactId>blog</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>Jacob Clark Blog</name>
<description>A blog for jacob.uk.com</description>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
<version>1.0.2</version>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>javax.persistence</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.jpa</artifactId>
<version>2.6.0-M3</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.33</version>
</dependency>
</dependencies>
</project>
persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="blog" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>uk.com.jacob.blog.models.Post</class>
<properties>
<property name="javax.persistence.jdbc.url"
value="jdbc:mysql://localhost:3306/jpadb"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="root"/>
<property name="javax.persistence.jdbc.driver"
value="com.mysql.jdbc.Driver"/>
<property name="eclipselink.logging.level" value="FINE"/>
<property name="eclipselink.ddl-generation"
value="create-tables"/>
</properties>
</persistence-unit>
</persistence>
Post Bean
package com.uk.jacob.blog.models;
import java.util.Date;
import javax.persistence.*;
#Entity
public class Post {
#Id
private int _id;
private String _title;
private String _author;
private String _body;
private Date _published;
public int getId(){
return _id;
}
public void setId(int _id){
this._id = _id;
}
public String getTitle() {
return _title;
}
public void setTitle(String _title) {
this._title = _title;
}
public String getAuthor() {
return _author;
}
public void setAuthor(String _author) {
this._author = _author;
}
public String getBody() {
return _body;
}
public void setBody(String _body) {
this._body = _body;
}
public Date getPublished() {
return _published;
}
public void setPublished(Date _published) {
this._published = _published;
}
}
Post Controller
package com.uk.jacob.blog.controllers;
import javax.persistence.*;
import com.uk.jacob.blog.models.Post;
public class PostController {
private EntityManagerFactory emf = Persistence.createEntityManagerFactory("blog");
private EntityManager em = emf.createEntityManager();
private EntityTransaction tx = em.getTransaction();
public Post createPost(Post post){
tx.begin();
em.persist(post);
tx.commit();
return post;
}
public Post getPost(int id){
return em.find(Post.class, id);
}
public void removePost(Post post){
em.remove(em.merge(post));
}
public void updatePost(Post post){
tx.begin();
Post postToBeUpdated = em.merge(post);
tx.commit();
}
}
It's because of you don't have eclipselink dependency in your pom.xml. Also
You don't need
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
<version>1.0.2</version>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>javax.persistence</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.jpa</artifactId>
<version>2.6.0-M3</version>
</dependency>
just
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>eclipselink</artifactId>
<version>2.4.2</version>
</dependency>
is enough (version may change)

How to validate model data with JPA?

I am trying to get JPA validation to work, however it seems that the validation annotations are ignored. I found this example of JPA validation on SO: JPA Entity Validation, but it does not work for me. The #NotNull and #Size annotations seem to be ignored.
As in the answer mentioned above I use only two classes:
Customer.java:
package com.validation.test;
import javax.persistence.*;
import javax.validation.constraints.*;
#Entity
#Table(name = "T_CUSTOMER")
public class Customer {
#Id
#NotNull
#SequenceGenerator(name = "customerIdSeq", sequenceName = "T_CUSTOMER_ID_SEQ", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "customerIdSeq")
private Long id;
#NotNull
#Size(min = 3, max = 80)
private String name;
public Customer() {};
public Customer(String name) {
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
CustomerTest.java:
package com.validation.test.test;
import static org.junit.Assert.*;
import javax.persistence.*;
import javax.validation.*;
import javax.validation.constraints.Size;
import org.junit.*;
import com.validation.test.Customer;
public class CustomerTest {
private static EntityManagerFactory emf;
private EntityManager em;
#BeforeClass
public static void createEntityManagerFactory() {
emf = Persistence.createEntityManagerFactory("testPU");
}
#AfterClass
public static void closeEntityManagerFactory() {
emf.close();
}
#Before
public void beginTransaction() {
em = emf.createEntityManager();
em.getTransaction().begin();
}
#After
public void rollbackTransaction() {
if (em.getTransaction().isActive()) {
em.getTransaction().rollback();
}
if (em.isOpen()) {
em.close();
}
}
#Test
public void nameTooShort() {
try {
Customer customer = new Customer("bo");
em.persist(customer);
em.flush();
fail("Expected ConstraintViolationException wasn't thrown.");
} catch (ConstraintViolationException e) {
assertEquals(1, e.getConstraintViolations().size());
ConstraintViolation<?> violation = e.getConstraintViolations().iterator().next();
assertEquals("name", violation.getPropertyPath().toString());
assertEquals(Size.class, violation.getConstraintDescriptor().getAnnotation().annotationType());
}
}
}
pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.validation.test</groupId>
<artifactId>test</artifactId>
<version>0.0.1-SNAPSHOT</version>
<repositories>
<repository>
<id>maven2-repository.java.net</id>
<name>Java.net Repository for Maven</name>
<url>http://download.java.net/maven/2/</url>
<layout>default</layout>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>javax.persistence</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>eclipselink</artifactId>
<version>1.2.0</version>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc5</artifactId>
<version>11.2.0.2.0</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.0.0.GA</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.0.3.Final</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>wwd-bs</finalName>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.16</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0"
xmlns="http://java.sun.com/xml/ns/persistence">
<persistence-unit name="testPU" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>com.validation.test.Customer</class>
<properties>
<property name="eclipselink.logging.level" value="FINE" />
<property name="javax.persistence.jdbc.driver" value="oracle.jdbc.OracleDriver" />
<property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:#localhost:1521:orcl" />
<property name="javax.persistence.jdbc.user" value="user" />
<property name="javax.persistence.jdbc.password" value="password" />
<property name="eclipselink.logging.level" value="INFO" />
</properties>
</persistence-unit>
</persistence>
The test fails at the fail(...) so the exception is never thrown.
How can I make (any) validation work with JPA? I cannot use Hibernate or Spring.
Thank you for your help
EDIT: added hibernate-validator to pom.xml (with no effect)
Add this to your pom.xmls.
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>4.2.0.Final</version>
<exclusions>
<exclusion>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.0.0.GA</version>
</dependency>
And set validation property to AUTO this must to be enable in persistence.xml
<property name="javax.persistence.validation.mode" value="AUTO" />
Or do it progrmatically.
final Set<ConstraintViolation<Object>> errors = validator.validate(object, classes);
Do you have a runtime implementation of the validator on your classpath? Typically people seem to use hibernate validator. (e.g. indeed by adding hibernate-validator to your pom.xml)
edit: Your version of EclipseLink also looks quite old, it should be a JPA2 implementation. If it is a JPA1 implementation, you should register your own event listener, which will be a bit more work. You can find some hints in the eclipse docs (scroll down to JPA section), but it looks like you'll have to slightly edit the standard validators to make it work. This blog might be helpful.

Categories

Resources