Showing posts with label JPA. Show all posts
Showing posts with label JPA. Show all posts

Thursday, November 7, 2019

JPA Parent child relationship

https://vladmihalcea.com/the-best-way-to-map-a-onetomany-association-with-jpa-and-hibernate/


a quick reminder to myself:

if Post -> PostComment is a Unidirectional association (Post has a List<PostComments; but PostComment has no reference to Post),
then the insertion of each PostComment is done in two phases (INSERT + UPDATE who sets the parentId on the child table).
For this reason, the parentId column CANNOT BE DECLARED AS NOT NULL.

I don't like that.... ultimately that column should NEVER be null...

On the other hand, if you setup a full bidirectional relationship, only ONE insert is done, and you can keep parentId as NOT NULL.
To achieve that, you must explicitely set the Post attribute on the PostComment entity, before you persist/merge (I think, at least)





Thursday, May 16, 2019

Jooq and QueryDSL as alternatives to JPQL, Panache,

HQL (and JPQL) both suck because they are not statically typed..."lack of type safety and absence of static query checking" "concatenation of strings which is usually very unsafe "

"Criteria Query API ended up very verbose and practically unreadable. "


https://www.jooq.org/

"jOOQ generates Java code from your database and lets you build type safe SQL queries through its fluent API. "

So this is no ORM framework, it uses your DB as it is, it simply allows you to write safer SQL queries directly in a fluent Java API. No Hocus-Pocus, it's a 1-to-1 mapping between DB and Java.

Here some examples https://www.jooq.org/doc/3.11/manual-single-page/#jooq-in-7-steps



http://www.querydsl.com/

how to use it https://www.baeldung.com/querydsl-with-jpa-tutorial and https://www.baeldung.com/intro-to-querydsl



If you want to use Native SQL or JPQL in Spring: https://www.baeldung.com/spring-data-jpa-query


This is the horribly verbose JPA Criteria API https://www.baeldung.com/hibernate-criteria-queries
" the main and most hard-hitting advantage of Criteria queries over HQL is the nice, clean, Object Oriented API."




Monday, May 6, 2019

Panache as a wrapper for Hibernate

https://quarkus.io/guides/hibernate-orm-panache-guide

https://developers.redhat.com/courses/quarkus/effective-data-hibernate-and-panache-quarkus/

The product seems very well conceived, it really streamlines your JPA code.

One more aspect where the Java world has completely screwed up, is the 20 different ways you can implement DB queries....
ah if only ORM had been embedded into the language from the beginning, we would be dealing with a single persistence framework.



Saturday, April 7, 2018

H2 autogenerating unique IDs from Sequence

if you have annotated the ID with

import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Entity;

@Entity
@Table(uniqueConstraints = @UniqueConstraint(columnNames = "ID"), name = "VOCABULARY")
public class Vocabulary implements Serializable {

@Id
@GeneratedValue
private Long id;

and declared the ID as
CREATE TABLE "VOCABULARY" (
    "ID" NUMBER(10,0) NOT NULL
...
)
CREATE UNIQUE INDEX "VOCABULARY_UNIQ_ID" ON "VOCABULARY" ("ID") ;
ALTER TABLE "VOCABULARY" ADD PRIMARY KEY ("ID");

this is not enough... you will get this when you try to insert a new record:

org.h2.jdbc.JdbcSQLException: Sequence "HIBERNATE_SEQUENCE" not found; SQL statement:
call next value for hibernate_sequence [90036-197]
        at org.h2.message.DbException.getJdbcSQLException(DbException.java:357)
        at org.h2.message.DbException.get(DbException.java:179)
        at org.h2.message.DbException.get(DbException.java:155)
        at org.h2.command.Parser.readSequence(Parser.java:5970)
        at org.h2.command.Parser.readTerm(Parser.java:3131)
        at org.h2.command.Parser.readFactor(Parser.java:2587)
        at org.h2.command.Parser.readSum(Parser.java:2574)
        at org.h2.command.Parser.readConcat(Parser.java:2544)
        at org.h2.command.Parser.readCondition(Parser.java:2370)
        at org.h2.command.Parser.readAnd(Parser.java:2342)
        at org.h2.command.Parser.readExpression(Parser.java:2334)
        at org.h2.command.Parser.parseCall(Parser.java:4854)
        at org.h2.command.Parser.parsePrepared(Parser.java:382)
        at org.h2.command.Parser.parse(Parser.java:335)
        at org.h2.command.Parser.parse(Parser.java:307)
        at org.h2.command.Parser.prepareCommand(Parser.java:278)
        at org.h2.engine.Session.prepareLocal(Session.java:611)
        at org.h2.server.TcpServerThread.process(TcpServerThread.java:271)
        at org.h2.server.TcpServerThread.run(TcpServerThread.java:165)
        at java.lang.Thread.run(Thread.java:748)

        at org.h2.engine.SessionRemote.done(SessionRemote.java:624)
        at org.h2.command.CommandRemote.prepare(CommandRemote.java:68)
        at org.h2.command.CommandRemote.(CommandRemote.java:45)
        at org.h2.engine.SessionRemote.prepareCommand(SessionRemote.java:494)
        at org.h2.jdbc.JdbcConnection.prepareCommand(JdbcConnection.java:1203)
        at org.h2.jdbc.JdbcPreparedStatement.(JdbcPreparedStatement.java:73)
        at org.h2.jdbc.JdbcConnection.prepareStatement(JdbcConnection.java:676)
        at org.jboss.jca.adapters.jdbc.BaseWrapperManagedConnection.doPrepareStatement(BaseWrapperManagedConnection.java:757)
        at org.jboss.jca.adapters.jdbc.BaseWrapperManagedConnection.prepareStatement(BaseWrapperManagedConnection.java:743)
        at org.jboss.jca.adapters.jdbc.WrappedConnection.prepareStatement(WrappedConnection.java:454)
        at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$1.doPrepare(StatementPreparerImpl.java:87)
        at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$StatementPreparationTemplate.prepareStatement(StatementPreparerImpl.java:172)



Solution is:

CREATE SEQUENCE VOCABULARY_SEQUENCE_ID START WITH (select max(ID) + 1 from VOCABULARY);

(this allows me to prepopulate the VOCABULARY with static values, and initialize the sequence accordingly)

and in Java

@Id
@SequenceGenerator(name= "VOCABULARY_SEQUENCE", sequenceName = "VOCABULARY_SEQUENCE_ID", initialValue=1, allocationSize = 1)
@GeneratedValue(strategy=GenerationType.AUTO, generator="VOCABULARY_SEQUENCE")
private Long id;



Why in 2018 such common things have to be still so complicated, no clue, something is really going wrong in the Java world... maybe using Spring it's only a matter of 1 annotation... no clue...





Friday, April 6, 2018

Eclipse generate JPA entities from DB

Unfortunately there doesn't seem to exist a tool to generate JPA Entities directly from SQL. Weird!
So you have to start by populating a real schema.

Create a Java project

Configure "Targeted Runtimes" with "Wildfly 11 Runtime"

Configure Project, Facets, and select JPA (ignore the "further configuration available")

Right-click on Project, you should see "JPA Tools", "Generate Entities from tables"



When I was young I was thinking of 2017 as the age of teletransportation and instant cure for all diseases. Instead it's the age of wasting hours for a Maven configuration. I bet the Cro-Magnon were more technologically savvy than the Maven folks.




Saturday, November 18, 2017

JPA, Hibernate, Dali and the Metamodel

When building Query criterias, you want to avoid using the String "email" to identify an Entity field... the day you change the field "email" into "mailaddress", your code still compiles but breaks in PROD... ugly... unless you wrote tests... but I prefer when it breaks during compile!

So you must use https://docs.jboss.org/hibernate/entitymanager/3.5/reference/en/html/querycriteria.html "the static form of metamodel reference", that is using an automatically generated class

https://stackoverflow.com/questions/3037593/how-to-generate-jpa-2-0-metamodel

Example:

package org.pierre.calories.entities;

import java.io.Serializable;
import javax.persistence.*;
import java.math.BigDecimal;


/**
 * The persistent class for the USERS database table.
 * 
 */
@Entity
@Table(name="USERS")
@NamedQuery(name="User.findAll", query="SELECT u FROM User u")
public class User implements Serializable {
 private static final long serialVersionUID = 1L;

 @Id
 @GeneratedValue
 private String userid;

 private BigDecimal expectedcalperday;
 
 private String email;

 public String getEmail() {
  return email;
 }

 public void setEmail(String email) {
  this.email = email;
 }

 public User() {
 }

 public User(String userid, BigDecimal expectedcalperday) {
  super();
  this.userid = userid;
  this.expectedcalperday = expectedcalperday;
 }

 public String getUserid() {
  return this.userid;
 }

 public void setUserid(String userid) {
  this.userid = userid;
 }

 public BigDecimal getExpectedcalperday() {
  return this.expectedcalperday;
 }

 public void setExpectedcalperday(BigDecimal expectedcalperday) {
  this.expectedcalperday = expectedcalperday;
 }

}



and its metamodel

package org.pierre.calories.entities;

import java.math.BigDecimal;
import javax.annotation.Generated;
import javax.persistence.metamodel.SingularAttribute;
import javax.persistence.metamodel.StaticMetamodel;

@Generated(value="Dali", date="2017-11-18T11:02:45.198+0100")
@StaticMetamodel(User.class)
public class User_ {
 public static volatile SingularAttribute<User, String> userid;
 public static volatile SingularAttribute<User, BigDecimal> expectedcalperday;
 public static volatile SingularAttribute<User, String> email;
}


To achieve this in Eclipse: Project/Properties and then:





The multitude of very complicated options (in Maven for instance) to achieve the same EASY result is just one more evidence of the very pathetic state of IT in 2017.... a huge spread of technologies and product to achieve really basic results.... the notion of metadata associated to persistence was around already 25 years ago, it's sad to see that we still don't have proper engineering and consolidated practice.

At this point I can write my logic like this:

package org.pierre.calories.database;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.persistence.EntityManager;

import org.pierre.calories.entities.Meal;
import org.pierre.calories.entities.User;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;


@ApplicationScoped
public class CaloriesRepository {

    @Inject
    private EntityManager em;
    
    public Meal findMealById(Long id) {
        return em.find(Meal.class, id);
    }
    
    public User findUserById(Long id) {
        return em.find(User.class, id);
    }
        
    public User findUserByEmail(String email) {
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<User> criteria = cb.createQuery(User.class);
        Root<User> rootUser = criteria.from(User.class);
        CriteriaQuery<User> select = criteria.select(rootUser);
//OLD SCHOOL  CriteriaQuery<User> emailresult = select.where(cb.equal(rootUser.get("email"), email));
        CriteriaQuery<User> emailresult = select.where(cb.equal(rootUser.get(User_.email), email));
        return em.createQuery(emailresult).getSingleResult();
    }  
    
}


Of course there are much easier ways to achieve the same result, like JPQL https://en.wikipedia.org/wiki/Java_Persistence_Query_Language




Saturday, October 28, 2017

Setting up Maven to retrieve ojdbc8.jar

googling around in StackOverflow there is a huge variety of approaches to this very common problem: you must add the artifact to your build, but it's not available in Maven Central.... what to do?

Some resort to downloading it manually and deploying it to the local Maven repo. Some even include the file in their WEB-INF/lib folder in their SCM project. Some use some third party public repositories (like Atlassian, code.lds.org, ... ) who graciously host these artifacts.... all fine when you play on your PC, but in a serious company with strict security control all this would not be allowed. Some folks simply cowboy-style put it somewhere in their HD and add the external JAR to Eclipse.... what happens next, they don't really care, as long as it works on their machine.

Oracle hosts these artifacts in their Public Oracle Maven repository, but you need to authenticate yourself (for which reason, it's totally obscure to me!)

https://docs.oracle.com/middleware/1213/core/MAVEN/config_maven_repo.htm#MAVEN9016 here how to setup maven to connect to the Oracle repo (basically: in settings.xml you have to declare the server maven.oracle.com authenticating with your user, the in your pom.xml you must declare a rerpository with id matching this maven.oracle.com server, then a pluginRepository with id again maven.oracle.com. At this point you can declare the dependency

<dependency>
   <groupId>com.oracle.jdbc</groupId>
   <artifactId>ojdbc8</artifactId>
   <version>12.2.0.1</version>
  </dependency>

This post explains it in a lot of detail https://blogs.oracle.com/dev2dev/get-oracle-jdbc-drivers-and-ucp-from-oracle-maven-repository-without-ides

To make things much more complicated, the repository is not browsable https://maven.oracle.com/com/oracle/ojdbc8/ ... how to determine it content, no clue!


See also https://stackoverflow.com/questions/9898499/oracle-jdbc-ojdbc6-jar-as-a-maven-dependency] and https://stackoverflow.com/questions/1074869/find-oracle-jdbc-driver-in-maven-repository

https://mvnrepository.com/artifact/com.oracle/ojdbc6/12.1.0.1-atlassian-hosted to get ojdbc6.jar from maven (atlassian hosted!)

https://developer.atlassian.com/docs/advanced-topics/working-with-maven/atlassian-maven-repositories to configure atlassian repo in pom.xml



IMPORTANT: when running in Eclipse, make sure you are NOT using the Embedded installation of Maven while you are configuring an EXTERNAL Maven configuration.... this multiplicity of installations and configurations only makes the developer's life more miserable.... IMHO it's better to have an independent, external, universal installation rather than an embedded one.... again another major fuck-up in Eclipse design. Forget Eclipse, use Netbeans and Intellij.


CODE: a working pom.xml is available here https://github.com/vernetto/JavaMonAmour/tree/master/oracletest



Friday, December 9, 2016

EntityManager and statement timeout

We spoke here about Statement Timeout to set on a Datasource http://www.javamonamour.org/2013/04/statement-timeout-on-datasource.html

If you use an EntityManager, you don't have access to the javax.sql.Statement object. This is the beauty of abstraction (sarcasm here): it prevents you from using the full power of the underlying technology, and it forces you to awkward acrobatics.

I would give a try to javax.persistence.query.timeout

http://stackoverflow.com/questions/24244621/set-timeout-on-entitymanager-query

https://docs.jboss.org/hibernate/entitymanager/3.6/reference/en/html_single/


query.setHint("javax.persistence.query.timeout", 2000);



see https://docs.oracle.com/javaee/6/api/javax/persistence/Query.html

but it works (actually, they told me it doesn't work AT ALL with WebLogic 12 and Eclipse JPA) only if you use Queries with EntityManager....



Wednesday, May 2, 2012

Eclipse JPA, classpath needed

<classpathentry kind="lib" path="C:/Oracle/Middleware/wlserver_10.3/server/lib/weblogic.jar"/>

<classpathentry kind="lib" path="C:/Oracle/Middleware/modules/org.apache.openjpa_1.2.0.0_1-1-1-SNAPSHOT.jar"/>

<classpathentry kind="lib" path="C:/Oracle/Middleware/wlserver_10.3/server/lib/wlthint3client.jar"/>


not only, but running from Eclipse you should put weblogic.jar in the BOOTSTRAP classpath...

terrible, really terrible...


and don't forget to put
property name="eclipselink.target-database" value="org.eclipse.persistence.platform.database.OraclePlatform"

in the persistence.xml

Saturday, April 28, 2012

Sample EntityManager usage in Java and Python WLST

In Eclipse, create a JDBC Connection
show view Data Source Explorer
new Connection Profile (enter parameters for your schema)

New JPA project
JPA Tools, Generate Entities from Tables

you should have a persistence.xml which contains

<?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="ToplinkTest" transaction-type="RESOURCE_LOCAL">
  <class>com.osb.reporting.WliQsReportAttribute</class>
  <class>com.osb.reporting.WliQsReportData</class>
  <properties>
   <property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:@localhost:1521:xe"/>
   <property name="javax.persistence.jdbc.user" value="DEV_SOAINFRA"/>
   <property name="javax.persistence.jdbc.password" value="DEV_SOAINFRA"/>
   <property name="javax.persistence.jdbc.driver" value="oracle.jdbc.OracleDriver"/>
  </properties>
 </persistence-unit>
</persistence>



You can now code the client:

package com.osb.reporting.client;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;

import com.osb.reporting.WliQsReportAttribute;

public class ReportingClient {
 public static void main(String[] args) throws ClassNotFoundException {
  EntityManagerFactory emf = Persistence.createEntityManagerFactory("ToplinkTest");
  EntityManager em = emf.createEntityManager();
  WliQsReportAttribute result = em.find(WliQsReportAttribute.class, "uuid:0e6fb58fc7c49289:5378b92d:134416bc5f5:-7fbe");
  System.out.println(result.getMsgLabels());
  Query fa = em.createQuery("select a from WliQsReportAttribute a");
  List res = fa.getResultList();
  for (Object el : res) {
   System.out.println( ((WliQsReportAttribute)el).getMsgLabels());
  }
 }
}



you will need to add the JDBC driver to the classpath, like
C:\bea1035\wlserver_10.3\server\ext\jdbc\oracle\11g\ojdbc5_g.jar

In WLST, just add to the classpath the location from which you can access classes and META-INF (where persistence.xml is located).... like the build\classes directory.


package com.osb.reporting.client;

from javax.persistence import *
emf = Persistence.createEntityManagerFactory("CMBDModeling")
em = emf.createEntityManager()
q = em.createQuery("select envs from Nesoa2Env envs")
res = q.getResultList()
for i in res:
   print i.envname

so the message is: you can easily use JPA in WLST and get rid of all that horrible pain of reading property files, by accessing directly a DB

Tuesday, April 5, 2011

org.hibernate.LazyInitializationException: failed to lazily initialize a collection


org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: acme.domain.model.Bla.mumbles, no session or session was closed
at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:358)
at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:350)
at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:343)
at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:86)
at org.hibernate.collection.PersistentSet.iterator(PersistentSet.java:163)




Entity Bla contains a collection of Mumbles. The OneToMany annotation by default uses a LAZY loading approach.

If in your client layer you try to do a bla.getMumbles(), you get the exception LazyInitializationException. The session was closed in the EJB, and in the client you have only a detached entity.
To avoid the problem, in the EJB do a

bla.getMumbles().size();

(bla.getMumbles() is not enough!)


This will explicitly load ALL mumbles and the client will be happy.

Monday, March 14, 2011

ManyToOne, OneToMany, ManyToMany

http://download.oracle.com/javaee/6/api/javax/persistence/ManyToOne.html

@ManyToOne(optional=false)
@JoinColumn(name="CUST_ID", nullable=false, updatable=false)
public Customer getCustomer() { return customer; }



http://download.oracle.com/javaee/6/api/javax/persistence/OneToMany.html

@OneToMany(cascade=ALL, mappedBy="customer")
public Set getOrders() { return orders; }



the first is always "me", the second is "the other"

ManyToOne means "there are many of me for one of them" -> hence I have only 1 of them, and he has a Set of me

OneToMany means "there is one of me for many of them" -> hence I have a Set of them


http://download.oracle.com/javaee/6/api/javax/persistence/ManyToMany.html

@ManyToMany
@JoinTable(name="CUST_PHONES")
public Set getPhones() { return phones; }


I have a Set of them, and they have a Set of me

com.arjuna.ats.internal.jta.transaction.arjunacore.inactive

Arjuna is the JBoss transaction manager

http://management-platform.blogspot.com/2008/11/transaction-timeouts-and-ejb3jpa.html


the entire stacktrace is:

11:13:43,774 WARN [arjLoggerI18N] [com.arjuna.ats.arjuna.coordinator.BasicActio
n_58] - Abort of action id a647bde:4e9:4d7de8ef:30 invoked while multiple threads active within it.
11:13:43,790 WARN [arjLoggerI18N] [com.arjuna.ats.arjuna.coordinator.CheckedAct
ion_2] - CheckedAction::check - atomic action a647bde:4e9:4d7de8ef:30 aborting with 1 threads active!
11:13:44,274 WARN [arjLoggerI18N] [com.arjuna.ats.arjuna.coordinator.BasicActio
n_40] - Abort called on already aborted atomic action a647bde:4e9:4d7de8ef:30
11:13:44,337 FATAL [TechnicalExceptionHandler] Technical exception [7b2b91d6-ab3
f-4cb6-9bc1-3ae8302d44c5] occured:
java.lang.IllegalStateException: [com.arjuna.ats.internal.jta.transaction.arjuna
core.inactive] [com.arjuna.ats.internal.jta.transaction.arjunacore.inactive] The
transaction is not active!

at com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionImple.c
ommitAndDisassociate(TransactionImple.java:1379)
at com.arjuna.ats.internal.jta.transaction.arjunacore.BaseTransaction.co
mmit(BaseTransaction.java:135)
at com.arjuna.ats.jbossatx.BaseTransactionManagerDelegate.commit(BaseTra
nsactionManagerDelegate.java:87)
at org.jboss.aspects.tx.TxPolicy.endTransaction(TxPolicy.java:175)
at org.jboss.aspects.tx.TxPolicy.invokeInOurTx(TxPolicy.java:87)
at org.jboss.aspects.tx.TxInterceptor$Required.invoke(TxInterceptor.java
:191)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.
java:101)
at org.jboss.aspects.tx.TxPropagationInterceptor.invoke(TxPropagationInt
erceptor.java:95)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.
java:101)
at org.jboss.ejb3.stateless.StatelessInstanceInterceptor.invoke(Stateles
sInstanceInterceptor.java:62)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.
java:101)
at org.jboss.aspects.security.AuthenticationInterceptor.invoke(Authentic
ationInterceptor.java:77)
at org.jboss.ejb3.security.Ejb3AuthenticationInterceptor.invoke(Ejb3Auth
enticationInterceptor.java:110)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.
java:101)
at org.jboss.ejb3.ENCPropagationInterceptor.invoke(ENCPropagationInterce
ptor.java:46)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.
java:101)
at org.jboss.ejb3.asynchronous.AsynchronousInterceptor.invoke(Asynchrono
usInterceptor.java:106)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.
java:101)
at org.jboss.ejb3.stateless.StatelessContainer.localInvoke(StatelessCont
ainer.java:240)
at org.jboss.ejb3.stateless.StatelessContainer.localInvoke(StatelessCont
ainer.java:210)
at org.jboss.ejb3.stateless.StatelessLocalProxy.invoke(StatelessLocalPro
xy.java:84)

Wednesday, March 2, 2011

detached entity passed to persist

well, if your entity has already an ID, and you invoke
entitymanager.persist(bla)

Hibernate will think you are trying to persist an already existing entity, and he will react giving this stern and cryptic error message.

Just set the ID to null and you will smile again.

When mapping an entity to another, NEVER map the ID!

Monday, February 14, 2011

JPA mapping boolean to CHAR(1) yes_no

After having googled around and found this and this, I have decided for the simplest possible solution: use a char in the Entity and expose it with a boolean getter/setter - anyway JPA uses "field" access to the Entity, so she is not disturbed by my setters and getters.

private char sysparam = 'N';

public void setSysparam(boolean sysparam) {
 this.sysparam = sysparam ? 'Y' : 'N';
}

public boolean getSysparam() {
 return sysparam == 'Y';
}



Incidentally all my boolean fields are NOT NULL, so I use directly a boolean rather than a Boolean.

It's a shame that JPA doesn't cover something so basic. Everybody knows that Oracle doesn't support a BOOLEAN data type; so I expect everyone is having the same problem.

Friday, February 11, 2011

JPA Entity: extending vs embedding

http://en.wikibooks.org/wiki/Java_Persistence/Embeddables#Example_of_an_Embeddable_object_annotations



JPA defines 2 annotations: @Embeddable and @Embedded
This is a great way to COMPOSE objects - rather than inheriting.

Suppose you have to incorporate in your entities several features:
tracking, logical deletion, id....

one solution is to stick all the co,,on features in a base abstract Entity.
The problem arises when not ALL Entities use ALL the features...; then you should introduce several base classes... this could soon become unmanageable.

The alternative is to Embed only the Embeddable entities that you want to incorporate.

The problem is that it's not easy to determine which Embeddable Entities are embedded in a given Entity.... while when using abstract classes or interfaces you can use instanceof.

Wednesday, February 9, 2011

All you wanted to know about JPA

http://en.wikibooks.org/wiki/Java_Persistence

it's a really good source of information... I love wikified information, so easy to navigate.

Thursday, February 3, 2011

java.lang.IllegalStateException: EMF has not been initialized yet!

have you remembered to setup your JTA Datasource in the persistence.xml ? Remember to provide the JNDI name for the DS, not the logical name.

Is it pointing to a valid DS in WebLogic?
Probably the EntityManagerFactory didn't start because of invalid DS. Check the logs.

Thanks Dimitri for pointing this out :o)

Saturday, August 28, 2010

Eclipse JPA project broken when mavenized: Invalid content (no root node)

My Eclipse JPA project was broken once mavenized: 
I get a message:
Invalid content (no root node)




I have had some allucinating time reading this
https://bugs.eclipse.org/bugs/show_bug.cgi?id=290929


How sad.... anyway I found a workaround to get rid of the message:
I copy META-INF/persistence.xml in all the source folders of my project (in my case, the src/test/java folder).


Long live Eclipse! Long live Maven! One day hopefully these products will be remembered as one of the biggest trash of history.... unfortunately these days we have to learn how to coexist with them, just like Iraqis learn to coexist with US Marines.

Saturday, July 17, 2010

JPA and primary key sequence generation

Nothing is easy...

I do:
create sequence GEO_MESSAGES_LOG_SEQ;

and I assign the primary key as "sequence generated".
This entails these annotations:

@Id
@SequenceGenerator(name="GEO_MESSAGES_LOG_ID_GENERATOR", sequenceName="GEO_MESSAGES_LOG_SEQ", allocationSize=1)
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="GEO_MESSAGES_LOG_ID_GENERATOR")


I immediately get this error:

Exception [TOPLINK-7027]

Exception Description: The sequence named [GEO_MESSAGES_LOG_SEQ] is setup incorrectly. Its increment does not match its pre-allocation size.



in @SequenceGenerator I add allocationSize=1

and things magically work... I suspect performance will not be great...