I am trying to make a add to wish list feature for my app but I keep getting this error:
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLIntegrityConstraintViolationException: Column 'WISH_ID' cannot accept a NULL value.
Error Code: -1
Call: INSERT INTO WISHLIST (BOOK_TITLE, CUSTOMER_ID) VALUES (?, ?)
bind => [2 parameters bound]
Query: InsertObjectQuery(dukesbookstore.entity.Wishlist[ wishId=null ])
ENTITY class:
#Entity
#Table(name = "WISHLIST")
#XmlRootElement
#NamedQueries(
{
#NamedQuery(name = "Wishlist.findByCustomerId", query = "SELECT w FROM Wishlist w WHERE w.customerId = :customerId"),
})
public class Wishlist implements Serializable
{
private static final long serialVersionUID = 1L;
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "WISH_ID")
private Integer wishId;
#Column(name = "CUSTOMER_ID")
private Integer customerId;
#Size(max = 35)
#Column(name = "BOOK_TITLE")
private String bookTitle;
public Wishlist()
{
}
public Integer getCustomerId()
{
return customerId;
}
public void setCustomerId(Integer customerId)
{
this.customerId = customerId;
}
public String getBookTitle()
{
return bookTitle;
}
public void setBookTitle(String bookTitle)
{
this.bookTitle = bookTitle;
}
}
and this is the code for creating a new wish:
public void createWishlist(String title,int cust_id)
{
Wishlist newWish = new Wishlist();
newWish.setBookTitle(title);
newWish.setCustomerId(cust_id);
em.persist(newWish);
}
I tried to look at other similar problems but they involves hibernate which i am not using. I have also tried various generation strategy such as AUTO,SEQUENCE,TABLE but all failed. I also have another entity named customer which is exactly same but it works fine though its created from a form.
Changing to AUTO generates this error:
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLSyntaxErrorException: Table/View 'SEQUENCE' does not exist.
Error Code: -1
Call: UPDATE SEQUENCE SET SEQ_COUNT = SEQ_COUNT + ? WHERE SEQ_NAME = ?
bind => [2 parameters bound]
Query: DataModifyQuery(name="SEQUENCE" sql="UPDATE SEQUENCE SET SEQ_COUNT = SEQ_COUNT + ? WHERE SEQ_NAME = ?")
root cause
java.sql.SQLSyntaxErrorException: Table/View 'SEQUENCE' does not exist.
root cause
org.apache.derby.client.am.SqlException: Table/View 'SEQUENCE' does not exist.
Persistence.xml incase relevant
<?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="myStorePU" transaction-type="JTA">
<jta-data-source>mydb</jta-data-source>
<class>myStore.entity.Book</class>
<class>myStore.entity.Customer</class>
<class>myStore.entity.Wishlist</class>
<properties>
<property name="javax.persistence.jdbc.user" value="APP"/>
<property name="javax.persistence.jdbc.password" value="APP"/>
<property name="eclipselink.logging.level" value="FINE"/>
</properties>
</persistence-unit>
Finally it is working now,
firstly, i had to delete the table that I created from netbeans db creation tool, which had a creation code like this, as seen by using "grab structure"
create table "APP".WISHLIST
(
WISH_ID NUMERIC(5) not null primary key,
CUSTOMER_ID NUMERIC(5),
BOOK_TITLE VARCHAR(100)
)
secondly, I added this code into my persistence.xml file
<property name="eclipselink.ddl-generation" value="create-tables"/>
This solved the problem as it created the table by it self, which have different creation code, as seen from its grab structure from auto creation:
create table "APP".WISHLIST
(
WISH_ID INTEGER default GENERATED_BY_DEFAULT not null primary key,
CUSTOMER_ID NUMERIC(5),
BOOK_TITLE VARCHAR(100)
)
So, basically should let netbeans create the table itself from entity but i was using "Create entity from table" features, for that i had to create the tables first in netbeans gui.
Thank you #Geziefer for all the help, I learned quite a bit from your help too.
This might be a "Non nullable attributes" in JPA single-table-inheritance problem. It might help and doesn't hurt to specify
#JoinTable(name = "[some join table name]",
joinColumns = {#JoinColumn(name = "[some ID column name]")},
inverseJoinColumns = {#JoinColumn(name = "[some different ID column name]")})
Related
I am new to working with databases and I have a Spring DATA JPA training project with HSQLDB that has 2 entities with child collections and many to many relationships.
One entity is called a Menu, and it contains a Dish list, and vice versa, a Dish contains a set of Menus to which it belongs.
When I try to insert a collection of dishes into a table, the Hibernate sends a separate call for each entity. Is there any way to optimize for Hibernate to send one complex query to save the entire child collection?
UPD.
Sorry for the mistake, actually I'm saving the Menu that contains the Dish collection, and not just saving the Dish collection.
Hibernate:
call next value for global_seq
Hibernate:
/* insert com.atanava.restaurants.model.Menu
*/ insert
into
menus
(date, restaurant_id, id)
values
(?, ?, ?)
Hibernate:
/* insert collection
row com.atanava.restaurants.model.Menu.dishes */ insert
into
dishes_menus
(menu_id, dish_id)
values
(?, ?)
Hibernate:
/* insert collection
row com.atanava.restaurants.model.Menu.dishes */ insert
into
dishes_menus
(menu_id, dish_id)
values
(?, ?)
Hibernate:
/* insert collection
row com.atanava.restaurants.model.Menu.dishes */ insert
into
dishes_menus
(menu_id, dish_id)
values
(?, ?)
Hibernate:
/* insert collection
row com.atanava.restaurants.model.Menu.dishes */ insert
into
dishes_menus
(menu_id, dish_id)
values
(?, ?)
Hibernate:
/* insert collection
row com.atanava.restaurants.model.Menu.dishes */ insert
into
dishes_menus
(menu_id, dish_id)
values
(?, ?)
Menu class:
#NamedQueries({
#NamedQuery(name = Menu.GET, query = "SELECT m FROM Menu m WHERE m.id=:id AND m.restaurant.id=:restaurantId"),
#NamedQuery(name = Menu.BY_RESTAURANT, query = "SELECT m FROM Menu m WHERE m.restaurant.id=:restaurantId ORDER BY m.date DESC"),
#NamedQuery(name = Menu.BY_DATE, query = "SELECT m FROM Menu m WHERE m.date=:date"),
#NamedQuery(name = Menu.BY_REST_AND_DATE, query = "SELECT m FROM Menu m WHERE m.restaurant.id=:restaurantId AND m.date=:date"),
#NamedQuery(name = Menu.DELETE, query = "DELETE FROM Menu m WHERE m.id=:id AND m.restaurant.id=:restaurantId"),
})
#Entity
#Table(name = "menus", uniqueConstraints = {#UniqueConstraint(columnNames = {"restaurant_id", "date"},
name = "restaurant_id_date_idx")})
public class Menu extends AbstractBaseEntity {
public static final String GET = "Menu.get";
public static final String BY_RESTAURANT = "Menu.getAllByRestaurant";
public static final String BY_DATE = "Menu.getAllByDate";
public static final String BY_REST_AND_DATE = "Menu.getByRestAndDate";
public static final String DELETE = "Menu.delete";
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "restaurant_id", nullable = false)
#OnDelete(action = OnDeleteAction.CASCADE)
#NotNull
private Restaurant restaurant;
#ManyToMany(fetch = FetchType.EAGER)
#Fetch(FetchMode.SUBSELECT)
#JoinTable(name = "dishes_menus",
joinColumns = #JoinColumn(name = "menu_id"),
inverseJoinColumns = #JoinColumn(name = "dish_id"))
private List<Dish> dishes;
#Column(name = "date", columnDefinition = "date default current_date", nullable = false)
#NotNull
private LocalDate date;
//constructors, getters, setters
}
Dish class:
#NamedQueries({
#NamedQuery(name = Dish.BY_RESTAURANT, query = "SELECT d FROM Dish d WHERE d.restaurant.id=:restaurantId ORDER BY d.name"),
})
#Entity
#Table(name = "dishes", uniqueConstraints = {#UniqueConstraint(columnNames = {"restaurant_id", "name"},
name = "unique_restaurant_id_dish_name_idx")})
public class Dish extends AbstractNamedEntity {
public static final String BY_RESTAURANT = "Dish.getAllByRestaurant";
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "restaurant_id", nullable = false)
#OnDelete(action = OnDeleteAction.CASCADE)
#NotNull
private Restaurant restaurant;
#Column(name = "price", nullable = false)
#NotNull
private Integer price;
#Column(name = "active", nullable = false, columnDefinition = "bool default true")
private boolean active = true;
#ManyToMany(fetch = FetchType.LAZY, mappedBy = "dishes")
Set<Menu> menus;
//constructors, getters, setters
}
Menu repository where I haven't overridden save method yet:
I save menu with original method
crudMenuRepository.save(menu)
#Transactional(readOnly = true)
public interface CrudMenuRepository extends JpaRepository<Menu, Integer> {
#Transactional
#Modifying
#Query(name = Menu.DELETE)
int delete(#Param("id") int id, #Param("restaurantId") int restaurantId);
#Query(name = Menu.GET)
Menu get(#Param("id") int id, #Param("restaurantId") int restaurantId);
#Query(name = Menu.BY_REST_AND_DATE)
Menu getByRestAndDate(#Param("restaurantId") int restaurantId, #Param("date") LocalDate date);
#Query(name = Menu.BY_RESTAURANT)
List<Menu> getAllByRestaurant(#Param("restaurantId") int restaurantId);
#Query(name = Menu.BY_DATE)
List<Menu> getAllByDate(#Param("date") LocalDate date);
}
Snippet of initDB.sql file:
CREATE TABLE dishes
(
id INTEGER GENERATED BY DEFAULT AS SEQUENCE GLOBAL_SEQ PRIMARY KEY,
restaurant_id INTEGER NOT NULL,
name VARCHAR(255) NOT NULL,
price INTEGER NOT NULL,
active BOOLEAN DEFAULT TRUE NOT NULL,
FOREIGN KEY (restaurant_id) REFERENCES restaurants (id) ON DELETE CASCADE
);
CREATE UNIQUE INDEX unique_restaurant_id_dish_name_idx on dishes (restaurant_id, name);
CREATE TABLE menus
(
id INTEGER GENERATED BY DEFAULT AS SEQUENCE GLOBAL_SEQ PRIMARY KEY,
restaurant_id INTEGER NOT NULL,
date DATE DEFAULT CURRENT_DATE NOT NULL,
CONSTRAINT restaurant_id_date_idx UNIQUE (restaurant_id, date),
FOREIGN KEY (restaurant_id) REFERENCES restaurants (id) ON DELETE CASCADE
);
CREATE TABLE dishes_menus
(
dish_id INTEGER NOT NULL,
menu_id INTEGER NOT NULL,
CONSTRAINT dish_id_menu_id_idx UNIQUE (dish_id, menu_id),
FOREIGN KEY (dish_id) REFERENCES dishes (id) ON DELETE CASCADE,
FOREIGN KEY (menu_id) REFERENCES menus (id) ON DELETE CASCADE
);
UPD2
Here is my spring-db.xml config:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<jdbc:initialize-database data-source="dataSource" enabled="${database.init}">
<jdbc:script location="${jdbc.initLocation}"/>
<jdbc:script encoding="utf-8" location="classpath:db/populateDB.sql"/>
</jdbc:initialize-database>
<context:property-placeholder location="classpath:db/hsqldb.properties" system-properties-mode="OVERRIDE"/>
<!--no pooling-->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource"
p:driverClassName="org.hsqldb.jdbcDriver"
p:url="${database.url}"
p:username="${database.username}"
p:password="${database.password}"/>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:dataSource-ref="dataSource"
p:packagesToScan="com.atanava.**.model">
<!--p:persistenceUnitName="persistenceUnit">-->
<property name="jpaPropertyMap">
<map>
<entry key="#{T(org.hibernate.cfg.AvailableSettings).FORMAT_SQL}" value="${hibernate.format_sql}"/>
<entry key="#{T(org.hibernate.cfg.AvailableSettings).USE_SQL_COMMENTS}" value="${hibernate.use_sql_comments}"/>
<entry key="#{T(org.hibernate.cfg.AvailableSettings).JPA_PROXY_COMPLIANCE}" value="false"/>
<!--<entry key="#{T(org.hibernate.cfg.AvailableSettings).HBM2DDL_AUTO}" value="${hibernate.hbm2ddl.auto}"/>-->
</map>
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" p:showSql="${jpa.showSql}">
</bean>
</property>
</bean>
<tx:annotation-driven/>
<!-- Transaction manager for a single JPA EntityManagerFactory (alternative to JTA) -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"
p:entityManagerFactory-ref="entityManagerFactory"/>
<context:component-scan base-package="com.atanava.**.repository**"/>
<jpa:repositories base-package="com.atanava.**.repository**"/>
</beans>
And here is a persistence.xml file that I created:
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.2"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
<persistence-unit name="menu-persistence-unit">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<class>com.atanava.restaurants.model.Menu</class>
<class>com.atanava.restaurants.model.Dish</class>
<properties>
<property name="hibernate.jdbc.batch_size" value="20"/>
</properties>
</persistence-unit>
</persistence>
You can find information about batching in the documentation: https://docs.jboss.org/hibernate/stable/orm/userguide/html_single/Hibernate_User_Guide.html#batch
Essentially, you just have to set the hibernate.jdbc.batch_size property in the persistence.xml to e.g. 20.
I am developing a REST web service in Java EE I am using: Glassfish 5.0 (build 25), MariaDB 10.4 and eclipselink (JPA 2.1)
here is my code:
commande_line table
CREATE TABLE IF NOT EXISTS `cooldb`.`commande_line` (
`id` INT NOT NULL AUTO_INCREMENT,
`quantity` INT NULL,
`discount` INT NULL,
`dish` INT NOT NULL,
`commande` INT NOT NULL,
PRIMARY KEY (`id`),
UNIQUE INDEX `id_UNIQUE` (`id` ASC),
INDEX `fk_commande_line_dish1_idx` (`dish` ASC),
INDEX `fk_commande_line_commande1_idx` (`commande` ASC),
CONSTRAINT `fk_commande_line_dish1`
FOREIGN KEY (`dish`)
REFERENCES `cooldb`.`dish` (`id`)
ON DELETE CASCADE
ON UPDATE CASCADE,
CONSTRAINT `fk_commande_line_commande1`
FOREIGN KEY (`commande`)
REFERENCES `cooldb`.`commande` (`id`)
ON DELETE CASCADE
ON UPDATE CASCADE)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;
persistance.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.2" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
<!-- Define Persistence Unit -->
<persistence-unit name="my_persistence_unit" transaction-type="JTA">
<jta-data-source>jdbc/mariadb</jta-data-source>
<class>com.yac.model.Address</class>
<class>com.yac.model.Commande</class>
<class>com.yac.model.CommandeLine</class>
<class>com.yac.model.Dish</class>
<class>com.yac.model.Dishtype</class>
<class>com.yac.model.Ingredient</class>
<class>com.yac.model.Payement</class>
<class>com.yac.model.Profil</class>
<class>com.yac.model.Restaurant</class>
<class>com.yac.model.Userapp</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
</properties>
</persistence-unit>
</persistence>
commandeline entity
public class CommandeLine implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id")
private Integer id;
#Column(name = "quantity")
private Integer quantity;
#Column(name = "discount")
private Integer discount;
#JoinColumn(name = "commande", referencedColumnName = "id")
#ManyToOne(optional = false)
private Commande commande;
#JoinColumn(name = "dish", referencedColumnName = "id")
#ManyToOne(optional = false)
private Dish dish;
//Constructor
// Setter and Getter
}
commandeline web service
#Stateless
#Path("commandeline")
public class CommandeLineFacadeREST extends AbstractFacade<CommandeLine> {
#PersistenceContext(unitName = "my_persistence_unit")
private EntityManager em;
public CommandeLineFacadeREST() {
super(CommandeLine.class);
}
#POST
#Override
#Consumes(MediaType.APPLICATION_JSON)
public void create(CommandeLine entity) {
super.create(entity);
}
#Override
protected EntityManager getEntityManager() {
return em;
}
}
AbstractFacade
public abstract class AbstractFacade<T> {
private Class<T> entityClass;
public AbstractFacade(Class<T> entityClass) {
this.entityClass = entityClass;
}
protected abstract EntityManager getEntityManager();
public void create(T entity) {
getEntityManager().persist(entity);
}
}
The problem is when I test my web service with Postman and I try to insert a record with a POST request
here is what I receive as error message:
Local Exception Stack:
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.7.0.v20170811-d680af5): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLSyntaxErrorException: (conn=158) Table 'cooldb.sequence' doesn't exist
Error Code: 1146
Call: UPDATE SEQUENCE SET SEQ_COUNT = SEQ_COUNT + ? WHERE SEQ_NAME = ?
bind => [2 parameters bound]
Query: DataModifyQuery(name="SEQ_GEN_SEQUENCE" sql="UPDATE SEQUENCE SET SEQ_COUNT = SEQ_COUNT + ? WHERE SEQ_NAME = ?") ...
I don't understand why the problem with SEQUANCE when I use #GeneratedValue (strategy = GenerationType.IDENTITY).
When I change with #GeneratedValue (strategy = GenerationType.SEQUENCE) and I create the table with the following script:
CREATE SEQUENCE SEQUANCE START WITH 1 INCREMENT BY 1;
by applying the solution shown in : Table 'customerjpa.sequence' doesn't exist JPA
but the same probleme
thank you in advance for your help.
The problem is solved using Chris comments, i just add the following line in my persistence.xml file:
<property name="eclipselink.target-database" value="MySQL"/>
Thank you very much Chris.
So my new persistence.xml file is:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.2" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
<!-- Define Persistence Unit -->
<persistence-unit name="my_persistence_unit" transaction-type="JTA">
<jta-data-source>jdbc/mariadb</jta-data-source>
<class>com.yac.model.Address</class>
<class>com.yac.model.Commande</class>
<class>com.yac.model.CommandeLine</class>
<class>com.yac.model.Dish</class>
<class>com.yac.model.Dishtype</class>
<class>com.yac.model.Ingredient</class>
<class>com.yac.model.Payement</class>
<class>com.yac.model.Profil</class>
<class>com.yac.model.Restaurant</class>
<class>com.yac.model.Userapp</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="eclipselink.target-database" value="MySQL"/>
</properties>
</persistence-unit>
</persistence>
I just specified the database platform in MySQL in the persistence.xml file of the moment MariaDB is based on it, because MariaDB is not mentioned in the list.
If there are other suggestions do not hesitate thank you.
Another Solution:
Add ?useMysqlMetadata=true to your JDBC URL connection as bellow:
<property name="URL" value="jdbc:mariadb://[HOST]:[PORT]/[DB NAME]?useMysqlMetadata=true"/>
that will make MariaDB use MySQL meta data and then eclipselink will detect it as MySQL.
I want to perform CRUD operation over Postgres 9 using Hibernate.
Entity:
#Entity
#Table(name = "MESSAGE_HISTORY_RECORD")
public class MessageHistoryRecord {
#EmbeddedId
private MessageCompoundKey compoundKey;
#Column
private String responseChannel;
#ElementCollection
private List<Trace> traces;
#Column
private byte[] payload;
//getters and setters
}
Composite Id entity:
#Embeddable
public class MessageCompoundKey implements Serializable {
private static final long serialVersionUID = 9084329307727034214L;
#Column
private String correlatedMsgId;
#Column
private String messageId;
#Column
private String endpointId;
//getters and setters
}
ElementCollection Entity:
#Embeddable
public class Trace implements Serializable{
private static final long serialVersionUID = 9084329307727034214L;
private Long timestamp;
private String description;
//getters and setters
}
I am using hibernate.hbm2ddl.auto=update to create schema for me.
It created tables for me:
CREATE TABLE "public"."message_history_record"
(
correlatedmsgid varchar(255) NOT NULL,
endpointid varchar(255) NOT NULL,
messageid varchar(255) NOT NULL,
payload bytea,
responsechannel varchar(255),
CONSTRAINT message_history_record_pkey PRIMARY KEY (correlatedmsgid,endpointid,messageid)
)
;
CREATE UNIQUE INDEX message_history_record_pkey ON "public"."message_history_record"
(
correlatedmsgid,
endpointid,
messageid
)
;
CREATE TABLE "public"."messagehistoryrecord_traces"
(
messagehistoryrecord_correlatedmsgid varchar(255) NOT NULL,
messagehistoryrecord_endpointid varchar(255) NOT NULL,
messagehistoryrecord_messageid varchar(255) NOT NULL,
description varchar(255),
timestamp bigint
)
On persisting any object, I did not find any entry in messagehistoryrecord_traces table.
Hibernate properties:
hibernate.connection.driver_class=org.postgresql.Driver
hibernate.connection.url=jdbc:postgresql://192.xx.xx.xx:5432/testdb
hibernate.connection.username=***
hibernate.connection.password=****
hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
hibernate.connection.pool_size=10
hibernate.show_sql=true
hibernate.hbm2ddl.auto=update
Persist sql :
Hibernate: insert into MESSAGE_HISTORY_RECORD (payload, responseChannel, correlatedMsgId, endpointId, messageId) values (?, ?, ?, ?, ?)
According to your configuration the defaults should apply for the table name, column names and join column names of the collection table. These defaults are constructed as follows:
Table name: name of the referencing entity, appended with an underscore and the name of the entity attribute that contains the element colletion ( MessageHistoryRecord_traces)
Join column: name of the referencing entity, appended
with an underscore and the name of the primary key column of the entity table.
This second case is only allowed if you have a single primary key field in the parent entity which is not the case in your case. So you have specify the join column yourself as follows (I renamed the collection table name and foreign key column names because they are too long for my database system):
#ElementCollection
#CollectionTable(name = "mhr_traces",
joinColumns={#JoinColumn(name="mhr_correlatedmsgid", referencedColumnName="correlatedmsgid"),
#JoinColumn(name="mhr_endpointid", referencedColumnName="endpointid"),
#JoinColumn(name = "mhr_messageid", referencedColumnName = "messageid")})
private List<Trace> traces = new ArrayList<>();
And one more thing: you have to implement the equals() and hashCode() methods for the primary key class if you haven't done yet (they are not visible in your post).
Your table creation script is also missing the foreign key definitino (add them manually if they are not generated automatically):
CONSTRAINT mrFK FOREIGN KEY (mhr_correlatedmsgid, mhr_endpointid, mhr_messageid) REFERENCES MESSAGE_HISTORY_RECORD (correlatedmsgid,endpointid,messageid)
Adjust it matching to your database syntax (I don't know PostgreSQL)
With these adjustments everything works for me; indeed on an Oracle database system and EclipseLink as persistence provider. I think it is not implementation specific
Did you add anything to your traces list or it was empty??
It is working for me with postgresql without any tweaks. With hbm2ddl.auto set to update, hibernate created the tables and foreign key relationship between them as well. Here is the sample code I used :
public class App
{
public static void main( String[] args )
{
System.out.println("Maven + Hibernate + Postgresql");
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
MessageCompoundKey cKey = new MessageCompoundKey();
cKey.setCorrelatedMsgId("correlatedMsgId_2");
cKey.setEndpointId("endpointId_2");
cKey.setMessageId("messageId_2");
MessageHistoryRecord record = new MessageHistoryRecord();
record.setResponseChannel("ArsenalFanTv");
List<Trace> traces = new ArrayList<>();
Trace t1 = new Trace();
t1.setDescription("description_1");
t1.setTimestamp(System.currentTimeMillis());
traces.add(t1);
Trace t2 = new Trace();
t2.setDescription("description_2");
t2.setTimestamp(System.currentTimeMillis());
traces.add(t2);
record.setCompoundKey(cKey);
record.setTraces(traces);
session.save(record);
session.getTransaction().commit();
}
}
and my configuration file (hibernate.cfg.xml) is as follows :
<hibernate-configuration>
<session-factory>
<!-- <property name="hibernate.bytecode.use_reflection_optimizer">false</property> -->
<property name="hibernate.connection.driver_class">org.postgresql.Driver</property>
<property name="hibernate.connection.password">****</property>
<property name="hibernate.connection.url">jdbc:postgresql://127.0.0.1:5432/testdb</property>
<property name="hibernate.connection.username">****</property>
<property name="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<mapping class="com.skm.schema.MessageHistoryRecord"></mapping>
</session-factory>
</hibernate-configuration>
I was using StatelessSession instead of session. As per the documentation:
A stateless session does not implement a first-level cache nor interact with any second-level cache, nor does it implement transactional write-behind or automatic dirty checking, nor do operations cascade to associated instances. Collections are ignored by a stateless session. Operations performed via a stateless session bypass Hibernate's event model and interceptors. Stateless sessions are vulnerable to data aliasing effects, due to the lack of a first-level cache.
More details can be found on this thread.
After using Session instead of StatelessSession, it worked.
I'm trying to apply one to one relationship between two entities
first entity:
Video and OrganzationVideo every OrganizationVideo has one video entity
So I did the following
first organization_video table
CREATE TABLE `organization_video` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
video table
CREATE TABLE `video` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`title` varchar(100) DEFAULT NULL,
// rest of table contents
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
then I added constraint in organization_video table
CONSTRAINT `FK_organization_video` FOREIGN KEY (`id`) REFERENCES `video` (`id`)
Then generated entities
Video.java
#Entity
#Table(name = "video")
public class Video extends Persistable<Long> {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id")
private Long id;
#OneToOne(cascade = CascadeType.ALL, mappedBy = "video")
private OrganizationVideo organizationVideo;
\\ rest of video contetns
}
OrganizationVideo.java
#Entity
#Table(name = "organization_video")
public class OrganizationVideo extends Persistable<Long> {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id")
private Long id;
#JoinColumn(name = "id", referencedColumnName = "id")
#OneToOne(optional = false)
private Video video;
\\ rest of organziation video contents
}
persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/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_1.xsd">
<persistence-unit name="Default_Persistence_Unit" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<non-jta-data-source>jdbc/defaultDataSource</non-jta-data-source>
<properties>
<property name="hibernate.transaction.auto_close_session" value="false"/>
<property name="hibernate.max_fetch_depth" value="0"/>
<property name="hibernate.connection.release_mode" value="auto"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
<property name="hibernate.cglib.use_reflection_optimizer" value="true"/>
</properties>
</persistence-unit>
</persistence>
everything worked perfectly when persisting objects
the issue is with the fetching query
StringBuilder queryStr = new StringBuilder("select v from Video v where v.organizationVideo is null");
Query query = getEntityManager().createQuery(queryStr.toString());
return query.getResultList();
The weird behavior is that this query fetches data once then doesn't fetch any data tried to use #PrimaryKeyJoinColumn and changed id generation type with no luck but indeed there is something wrong it's strange to see data once first time when I tried to remove is null from query it fetches data but with null value assigned to OrganizationVideo then why the query doesn't work except at first time.
You will have to check the SQL that is generated for the query, but I'm guessing that since the ID is the foreign key and it is autogenerated, inserting entities causes problems with your query. Try fixing your model first:
Either the OrganizationVideo ID needs to be set by the video relationship (if using JPA 2.0):
#Entity
#Table(name = "organization_video")
public class OrganizationVideo extends Persistable<Long> {
#Id
#JoinColumn(name = "id", referencedColumnName = "id")
#OneToOne(optional = false)
private Video video;
\\ rest of organziation video contents
}
That, or you make one of the ID mappings within OrganizationVideo insertable=false, updatable=false. if you do this, then you must set the other fields with in OrganizationVideo within the application yourself, and only after the Video instance has an ID value assigned. Since you are using identity, this means you would have to persist the vidoe, flush, and then use that value within the OrganizationVideo before it can be persisted.
It would be easier for your model if you could just add a foreign key to the OrganizationVideo table and use that to reference the Video ID.
I cannot resolve these new exceptions
Can not set java.lang.Integer field GcmRegistraionIdentity.gcmId to GcmRegistraionIdentity
org.hibernate.PropertyAccessException: could not get a field value by reflection getter of GcmRegistraionIdentity.gcmId
My Dynamic Web Project (Jee7) targeted to
GlassFish Server Open Source Edition 4.1 (build 13)
Hibernate
Hibernate Core {4.3.7.Final}
My Persistence.xml
<persistence version="2.1"
xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://www.oracle.com/webfolder/technetwork/jsc/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="testPU" transaction-type="JTA">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<jta-data-source>jdbc/testDB</jta-data-source>
<properties>
<property name="hibernate.transaction.jta.platform"
value="org.hibernate.service.jta.platform.internal.SunOneJtaPlatform" />
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
<property name="hibernate.show_sql" value="true" />
</properties>
</persistence-unit>
</persistence>
Heres my EDITED entity class (partial: e.g Getters/Setters NOT SHOWN)
#Entity
#Table(name = "gcm_registration")
public class GcmRegistraionIdentity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "gcm_id", unique = true, nullable = false, insertable = false, updatable = false)
private Integer gcmId;
#Column(name = "registration_id")
private String registraionId = null;
#Column(name = "created")
#Temporal(TemporalType.TIMESTAMP)
private Date created;
public Integer getGcmId() {
return gcmId;
}
public void setGcmId(final Integer gcmId) {
this.gcmId = gcmId;
}
Mysql version is
Version 5.6.22 MySQL Community Server (GPL)
I am running on Mac OS X 10.10.1 (14B25) (Yosemite)
Heres my JAX-RS class
#Path("registrations")
#Stateless
public class RegistrationResource {
#PersistenceContext
private EntityManager mEntityManager;
#POST
#Path("gcm")
public void register(final RegistrationIdJson registrationId) {
final GcmRegistraionIdentity gcmRegistraionIdentity = new GcmRegistraionIdentity();
gcmRegistraionIdentity.setRegistraionId(registrationId.getRegistrationId());
mEntityManager.persist(gcmRegistraionIdentity);
}
}
Heres the DDL for my MySql table
CREATE TABLE `gcm_registration` (
`gcm_id` int(11) NOT NULL AUTO_INCREMENT,
`registration_id` varchar(1024) NOT NULL,
`created` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`gcm_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
I'll recommend a change in the name of id field.
Alter the table and update the column to "id". I think that "_id" is doing funny stuff on hibernate.
The solution was to replace
Hibernate Core {4.3.7.Final}
with
Hibernate Core {4.3.5.Final}
No other code or configuration changes were required