I try to test the persistence of some entities with an in-memory H2 DB but I recognized that #SequenceGenerator will never be invoked as it should be, neither when running by build platform, nor when running it with RunAs->JUnit test in Eclipse.
What I can say for sure is that the sequences are generated inside the H2 DB. I can even select them when I connect to this generated H2. So it's definitely not a problem inside H2 but with Hibernate.
(Usually Hibernate automatically assigns an ID when persisting an Entity which needs one).
The entity
#Entity
#Table(name = "HOUSE_USERDATA")
public class UserData {
#Id
#Column(name = "HU_ID")
#GeneratedValue(generator = "SEQ_HOUSE_USERDATA", strategy = GenerationType.SEQUENCE)
#SequenceGenerator(sequenceName = "SEQ_HOUSE_USERDATA", name = "SEQ_HOUSE_USERDATA", allocationSize = 2)
private Long huId;
#Column(name = "HU_DATA")
#Size(max = 1000)
private String m_data;
#ManyToOne
#JoinColumn(name = "HR_ID")
private Registry m_registry;
//more code [...]
}
The reference in the referencing Entity...
#OneToMany(mappedBy = "registry")
private List<UserData> userDataList;
The persistence unit...
<persistence-unit name="test" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>com.foo.bar.all.entity</class>
<!-- all entity references -->
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="hibernate.archive.autodetection" value="class"/>
<property name="hibernate.connection.username" value="sa"/>
<property name="hibernate.connection.password" value=""/>
<property name="hibernate.connection.driver_class" value="org.h2.Driver"/>
<property name="hibernate.connection.url"
value="jdbc:h2:inmemory;INIT=runscript from 'classpath:testscripts/drop_h2.sql'\;runscript from 'classpath:testscripts/create.sql'"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />
<property name="hibernate.hbm2ddl.auto" value="create-drop"/>
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.use_sql_comments" value="true" />
</properties>
</persistence-unit>
The invocation in JUnit test...
Registry registry = new Registry();
registry.setClientId("clientId");
List<UserData> userDataList = new ArrayList<>();
UserData userData1 = new UserData();
userData1.setData("User defined data 1.");
userData1.setRegistry(registry);
UserData userData2 = new UserData();
userData2.setData("User defined data 2.");
userData2.setRegistry(registry);
userDataList.add(userData1);
userDataList.add(userData2);
registry.setUserDataList(userDataList);
entityManager.persist(registry);
Registry result = entityManager.find(Registry.class, "clientId");
//MUST NOT BE NULL, BUT IS NULL
assertThat(result.getUserDataList().get(0).getId(), is(not(nullValue())))
Other values are persisted properly. Only the IDs were not generated. (I wonder why this test works at all for all the other values since the ID is defined as NOT NULL in the generated DB, so there should be a persistence exception or something else).
Any ides why the sequence generator does not generate anything (I tried GenerationType.AUTO as well, but no difference)?
When you are doing entityManager.persist(registry) that is what it is going to do, store the Registry and check all the mappings for that class. It will encounter the collection of UserData objects, but because there is no cascade property matching the PERSIST it will not store the UserData objects.
It will only store the top level Registry object. If you want to change this add cascade={CascadeType.ALL} or at least cascade={CascadeType.PERSIST} to the #OneToMany annotation, to tell Hibernate it also needs to check the collection for new elements and persist those.
Or first store the UserData elements, before storing the Registry.
Related
I face following issue while trying to write some JBehave BDD test. Scenario is the following:
Due to an MQ message some specific records should be saved into my database and some should be deleted from it. In my #When step I send the given message and in my #Then step I have some asserts to controll the result.
I face issue with the persist and update methods of Hibernate JPA, because it happens just after my code runs to my #Then step and so I got always false result. When I check it in debug mode, and check every recorsd which should be updated / deteled, they are fine.
I assume my asserts should be executed just after the transaction is committed into the database - but this is not the case as I can see.
Is there a way to set a delay or sleep time between database transactions?
Here is e.g. my delete method in my main project:
public void deleteByAbcId(final String Id) {
getEm().createNamedQuery(TABLE.NAMED_QUERY_DELETE_BY_ABC_ID)
.setParameter(Table.QUERY_PARAM_ABC_ID, Id)
.executeUpdate();
}
And in my BDD project I set up database connection as follows:
public class DatabaseService implements Closeable {
private EntityManagerFactory emf = null;
private EntityManager em = null;
/**
* This creates an entity manager based on the db connection parameters received in the argument
*/
public DatabaseService(Properties configuration) {
emf = Persistence.createEntityManagerFactory("project-pu", configuration);
em = emf.createEntityManager();
em.getTransaction().begin();
}
/**
* Returns the entity manager for the db connection
*/
public EntityManager getEm() {
return em;
}
In my assertion I use the following query to check if the given record was successfully removed from the db:
assertNull(dbHelper.findTableIdBasedOnAbcId(Serenity.sessionVariableCalled(ABC_ID)));
My dbHelper class looks like as following:
public class DbHelper {
private DatabaseService database;
private Configuration config = Configuration.getInstance();
public DbHelper() {
database = new DatabaseService(config.getDbProperties());
}
public String findTableIdBasedOnAbcId(String Id) throws Exception {
String query = "SELECT id FROM TABLE WHERE ABC_ID = ?1";
Query queryResult = database.getEm().createNativeQuery(query);
queryResult.setParameter(1, Id);
List<Long> list = (List<Long>) queryResult.getResultList();
if (!list.isEmpty()) {
return String.valueOf(list.get(0));
}
return null;
}
It always retunr the given record of the database, which gets not deleted.
This is the persistence xml of my main project:
<persistence-unit name="aaa-pu" transaction-type="JTA">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<jta-data-source>jdbc/aaaa-ds</jta-data-source>
<mapping-file>META-INF/orm.xml</mapping-file>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.transaction.jta.platform" value="org.hibernate.engine.transaction.jta.platform.internal.WeblogicJtaPlatform"/>
<property name="hibernate.hbm2ddl.auto" value="none"/>
<property name="hibernate.id.new_generator_mappings" value="false"/>
<property name="tomee.jpa.factory.lazy" value="true"/>
</properties>
</persistence-unit>
And this is the one of my BDD project:
<persistence-unit name="project-pu" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect" />
<property name="hibernate.connection.autocommit" value="false" />
<property name="hibernate.hbm2ddl.auto" value="none" />
<property name="hibernate.show_sql" value="false" />
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.generate_statistics" value="false"/>
</properties>
</persistence-unit>
Any idea, how to set transactions not to execute the assert method before the executeUpdate of Hibernate runs?
I tried to call the entityManager.getTransaction.commit method and then start a new one every time but no change.
Is there a way to lock the transaction until the executeUpdate is done and just after that allowing the select query? Or is it possible with JBehave to give a waiting or sleep time between steps?
Thank you.
I'm trying to use pure JPA 2.1 as a standardized way to generate db schema.
(Underlying database - Derby embedded, persistence provider - eclipseLink)
To check generated scripts I set <property name="javax.persistence.schema-generation-target" value="database-and-scripts"/>
And as a result I got it with some 'sequence' table within.
And although ... ERROR 42X05: Table/View 'SEQUENCE' does not exist.
Can somebody help to understand such a weird behavior?
maven dependencies:
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.jpa</artifactId>
<version>2.6.0</version>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derby</artifactId>
<version>10.9.1.0</version>
</dependency>
Entity:
import javax.persistence.*;
#Entity
public class Book {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String title;
// getters/setters/constructors
}
main body:
EntityManagerFactory emf = Persistence.createEntityManagerFactory("chapter04PU");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
em.persist(new Book("Neuromancer"));
tx.commit();
em.close();
emf.close();
persistence-unit:
<persistence-unit name="chapter04PU" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>Book</class>
<properties>
<!--<property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>-->
<property name="javax.persistence.schema-generation-action" value="drop-and-create"/>
<property name="javax.persistence.schema-generation-target" value="database-and-scripts"/>
<property name="javax.persistence.schema-generation.scripts.action" value="drop-and-create"/>
<property name="javax.persistence.schema-generation.scripts.create-target" value="create.sql"/>
<property name="javax.persistence.schema-generation.scripts.drop-target" value="delete.sql"/>
<property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:derby:chapter04DB;create=true"/>
</properties>
generated script file:
CREATE TABLE BOOK (ID BIGINT NOT NULL, TITLE VARCHAR(255), PRIMARY KEY (ID))
CREATE TABLE SEQUENCE (SEQ_NAME VARCHAR(50) NOT NULL, SEQ_COUNT DECIMAL(15), PRIMARY KEY (SEQ_NAME))
INSERT INTO SEQUENCE(SEQ_NAME, SEQ_COUNT) values ('SEQ_GEN', 0)
Update
After replacing:
<property name="javax.persistence.schema-generation-action" value="drop-and-create"/>
with:
<property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/>
I can 'normally' run app (with exit code 0).
But I still take this weird message while first run (with absent DB).
the second run is clear - no such messages.
Thanks a lot for your suggestion to use <property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/>!
As for the second problem, the main culprit here is #GeneratedValue(strategy=GenerationType.AUTO) which probably was a default value provided by IDE on entity creation. Given the way org.eclipse.persistence.jpa.PersistenceProvider processes this annotation (leading to the exception about non-existant 'SEQUENCE' table), the simplest solution would be to just use #GeneratedValue(strategy=GenerationType.IDENTITY) instead.
I have unittest to my java project.
My code uses hibernate.
When i run the test using junit - everything passes.
When I run the test using gradle - I get a mapping error:
Caused by: org.hibernate.MappingException: Unknown entity: linqmap.users.interfaces.model.UserRecord
and the class:
#Entity
#Table(name = "users")
public class UserRecord implements Serializable {
private static final long serialVersionUID = 1L;
public static short CLASS_VERSION = 3;
#Transient
public short objectVersion = CLASS_VERSION;
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "id")
public long ID;
#Column(name = "user_name")
public String userName;
#Column(name = "email")
public String email;
#Column(name = "full_name") // will be deprecated in the future
public String fullName;
#Column(name = "password")
public String password;
and a config file:
<persistence 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_1_0.xsd"
version="1.0">
<persistence-unit name="UsersDB">
<!-- The provider only needs to be set if you use several JPA providers <provider>org.hibernate.ejb.HibernatePersistence</provider> -->
<properties>
<!-- Scan for annotated classes and Hibernate mapping XML files -->
<property name="hibernate.archive.autodetection" value="class, hbm" />
<!-- SQL stdout logging <property name="hibernate.show_sql" value="true"/> <property name="hibernate.format_sql" value="true"/>
<property name="use_sql_comments" value="true"/> -->
<property name="hibernate.connection.driver_class" value="org.postgresql.Driver" />
<property name="hibernate.connection.url" value="dbc:postgresql://localhost:9992/israel" />
what can be missing in gradle?
I think the problem is not really with gradle. It's with the fact that the JPA spec stupidly requires that the classes of the entities are in the same jar/directory as the persistence.xml file. And since Gradle doesn't store the "compiled" resources in the same output directory as the compiled classes, Hibernate doesn't find the mapped entities.
Add this line to your gradle build, and it will probably be fine
sourceSets.main.output.resourcesDir = sourceSets.main.output.classesDir
I'm trying to use JPA in Wildfly (which uses Hibernate) with PostgreSQL. I turned on hibernate.show_sql so I can execute the same query in PgAdmin III.
The query is this one (EDIT: issuemanager_sch is the schema. Without it even in PgAdmin the query fails with "relation does not exist" error):
select issuetypet0_.id_issue_type as id_issue1_3_, issuetypet0_.name as name2_3_ from issuemanager_sch.issue_type issuetypet0_
When executed by Hibernate this is showed in both PostgreSQL log and Wildfly log :
relation "issuemanager_sch.issue_type" does not exist character 87
However, when I copy (to grant I'm executing the exact same query), paste and run the query in PgAdmin III it's executed normally and I get the results.
What could possibly be wrong with my configurations? (I tried with both quoted and unquoted queries and the results are the same: fails for Hibernate, works in PgAdmin III)
persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" version="2.1">
<persistence-unit name="PersistenceManager" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<non-jta-data-source>java:/datasources/issuemanager_pg</non-jta-data-source>
<class>com.im.issuerepository.domain.IssueTO</class>
<class>com.im.issuerepository.domain.IssueTypeTO</class>
<class>com.im.userrepository.domain.UserTO</class>
<class>com.im.userrepository.domain.GroupTO</class>
<class>com.im.userrepository.domain.RoleTO</class>
<validation-mode>NONE</validation-mode>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQL9Dialect"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.default_schema" value="issuemanager_sch"/>
</properties>
</persistence-unit>
</persistence>
EDIT: issue_type table:
CREATE TABLE issuemanager_sch.issue_type
(
id_issue_type bigint NOT NULL DEFAULT nextval('issuemanager_sch.issue_type_seq'::regclass),
name text NOT NULL,
CONSTRAINT "PK_ISSUE_TYPE" PRIMARY KEY (id_issue_type)
)
EDIT: IssueTypeTO mapping:
#Entity
#Table(name = "issue_type")
public class IssueTypeTO implements Serializable{
#Id
#Column(name = "id_issue_type")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "issue_type_seq")
#SequenceGenerator(name = "issue_type_seq", sequenceName = "issue_type_seq", allocationSize = 1)
private Long idIssueType;
#Column(name = "name", length = 45)
private String name;
// getters and setters
}
Setup
I'm Using JPA 1.0, Spring 3.0.6 and hibernate 3.2.1 on JBoss 4.3.2. There are some EJBs which at some point call a DAO which tries to persist two entities.
Problem
The result is quite unexpected: The entities are not managed after calling .persist(entity).
The Funny thing is: A quite similar test app, which uses the same jars containing DAOs, Beans persistence.xml as the server application, persists everything just fine. The beans are managed after calling .persist().
The entities
I have a class Subscriber that has a SubscriberState.
#Entity
#Table(name = "subscriber")
public class Subscriber implements java.io.Serializable {
// all the other stuff
#ManyToOne
#JoinColumn(name = "status")
private SubscriberState state;
}
For legacy reasons the SubscriberState has a relation Subscriber.
#Entity
#Table(name = "subscriber_state")
public class SubscriberState implements java.io.Serializable {
// ...blah
#ManyToOne
#JoinColumn(name = "subscriber", nullable = false)
private Subscriber subscriber;
}
what i do to persist
Now i try to persist a subscriber, it will be unmanaged afer persist():
final Subscriber subscriber = new Subscriber();
// set up...
entityManager.persist(subscriber);
entityManager.contaons(subscriber); //will yield FALSE
Adding a SubscriberState will work. But only one side of the relation will be stored to DB:
SubscriberState subscriberState = new SubscriberState();
subscriberState.setSubscriber(subscriber);
entityManager.persist(subscriberState);
entityManager.merge(subscriber);
where SubscriberState.setSubscriber looks like this:
public void setSubscriber(final Subscriber subscriber) {
this.subscriber = subscriber;
subscriber.setState(this);
}
A look at the database shows me, that the SubscriberState knows it's Subscriber, but the Subscriber does not know it's State.
the config
Here's the (now modified and stripped down) persistence.xml:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
org.hibernate.ejb.HibernatePersistence
java:jdbc/SODS
<properties>
<property name="hibernate.dialect" value="${db.hibernate.dialect}" />
<property name="hibernate.validator.apply_to_ddl" value="false" />
<property name="hibernate.validator.autoregister_listeners" value="false" />
<property name="hibernate.cache.provider_class" value="org.jboss.ejb3.entity.TreeCacheProviderHook" />
<property name="hibernate.treecache.mbean.object_name" value="jboss.cache:service=EJB3EntityTreeCache" />
<property name="jboss.entity.manager.jndi.name" value="java:/SOEntityManager-${app.version}" />
<property name="jboss.entity.manager.factory.jndi.name" value="java:/SOEntityManagerFactory-${app.version}" />
<property name="hibernate.transaction.factory_class" value="org.hibernate.transaction.JTATransactionFactory" />
<property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JBossTransactionManagerLookup" />
</properties>
<class>com.stackoverflow.some.classes.i.cant.show.Here</class>
and here are the relevant parts of my spring context:
<context:annotation-config />
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />
<jee:jndi-lookup id="entityManagerFactory" jndi-name="java:/SOEntityManagerFactory-${app.version}" />
<jee:jndi-lookup id="entityManager" jndi-name="java:/SOEntityManager-${app.version}" />
<jee:jndi-lookup id="soDataSource" jndi-name="java:jdbc/SODS" />
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager" />
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.simple.SimpleJdbcTemplate">
<constructor-arg ref="soDataSource" />
</bean>
<context:component-scan base-package="blah - secret" />
<import resource="daoContext.xml" />
</beans>
Any ideas, why this config won't work?
I don't see use of #Transaction in your DAO or service layer
Adding a SubscriberState will work. But only one side of the relation will be stored to DB
You should use cascade option in
#ManyToOne(cascade = CascadeType.PERSIST)
#JoinColumn(name = "subscriber", nullable = false)
private Subscriber subscriber;
This will save both side of the relationship in persist operation
Also what I see is two unidirectional relationship, not one bidireccional, try to use mappedBy
#ManyToOne
#JoinColumn(name = "status")
private SubscriberState state;
Unless that is not what you want, but you should reconsider your design to made one side OneToMany and the other side ManyToOne, use mappedBy to define the source (owner) of the relationship
This happened to my application, JPA with MySQL. Load the appropriate database driver class in the property file.