JPA Mini Book – First Steps and detailed concepts

Reasons that led to the creation of JPA

One of the problems of the Object Orientation is how to map the objects as the database requires. It is possible to have a class with the name Car but its data is persisted in a table named TB_CAR. The table name is just the beginning of the problems, what if the Car class has the attribute “name” but in the database you find the column STR_NAME_CAR?

The basic Java framework to access the database is the JDBC. Unfortunately, with JDBC, a lot of hand work is needed to convert a database query result into Java classes.

Bellow it is a code that shows how to transform a JDBC query result into Car objects:

import java.sql.*;
import java.util.LinkedList;
import java.util.List;

public class MainWithJDBC {
	public static void main(String[] args) throws Exception {
		Class.forName("org.hsqldb.jdbcDriver");

		Connection connection = // get a valid connection

		Statement statement = connection.createStatement();

		ResultSet rs = statement.executeQuery("SELECT "Id", "Name" FROM "Car"");

		List<Car> cars = new LinkedList<Car>();

		while(rs.next()){
			Car car = new Car();
			car.setId(rs.getInt("Id"));
			car.setName(rs.getString("Name"));
			cars.add(car);
		}

		for (Car car : cars) {
			System.out.println("Car id: " + car.getId() + " Car Name: " + car.getName());
		}

		connection.close();
	}
}

In the code above it is possible to see all the code needed to transform a JDBC query result into classes. Imagine if this class had 30 attributes… To make the scenario even worse, imagine if a class with 30 attributes and with a relationship to another class that has 30 attributes. E.g. a Car class may have a list of Person and the class Person has 30 attributes to be populated.

Other disadvantage of JDBC is its portability. The query syntax will change from one database to another. With Oracle database the command ROWNUM is used to limit the amount of returned lines, but with SqlServer the command is TOP.

Application portability is a problematic issue when database native queries are used. There are solutions to this kind of problem, e.g. a file with the query could be stored outside the ear file. To each database vendor a sql specific file would be required.

It is possible to find other problems when developing with JDBC like: update a database table and its relationships, do not leave any orphans records or an easy way to use hierarchy.

50 thoughts on “JPA Mini Book – First Steps and detailed concepts

  1. I copied and pasted and generated a PDF file – let me know how to send it to you – so that you can upload
    Thanks for the wonderful information and sharing your knowledge

  2. Olá. Há realmente necessidade de colocar @IdClass na Entidade?

    Usando apenas 3 @Id aqui na minha Entidade, o hibernate criou sozinho a chave composta. Qual seria o problema recorrente de fazer isso em uma @IdClass?

    • Davi, boa tarde.

      Infelizmente não sei falar se pode haver algum problema em sua abordagem.

      Nos dois livros que li que abordavam sobre JPA ambos falavam para utilizar o IdClass.

      Obrigado pela visita.

  3. Cara, como que faço pra salvar a entidade que tem N-N com atributos? Tudo quanto é coisa que eu faço da erro de detached…

    Eis minha ultima tentativa:

    public String editar(){
    prospecto = prospectoService.buscarProspectoComAcoes(prospecto.getId());

    log.debug(“Antes: “+prospecto.getProspectoCampos().size());

    List prospectoCampos = new ArrayList();

    for(ProspectoHelper hp : ProspectoHelper.extrairDadoDoModelo(dynaFormModelUniao)){
    ProspectoCampo pc = new ProspectoCampo();
    pc.setCampo(campoService.findOne(hp.getPropertyFilter().getCampo().getId()));
    pc.setValor(hp.getPropertyFilter().getValue().toString());
    pc.setProspecto(prospecto);
    prospectoCampos.add(pc);
    }

    prospecto.setProspectoCampos(prospectoCampos);

    log.debug(“Depois: “+prospecto.getProspectoCampos().size());

    prospecto.adicionarAcao(acaoSelecionada);

    try{
    prospectoService.save(prospecto);
    }catch(Exception e){
    log.error(“Erro ao editar Prospecto!”, e);
    messageUtil.sendErrorMessageToUser(“global.error”, “global.insert.error”, e.getMessage());
    return null;
    }

    return getRadarPath();
    }

    Abraços

    • Marco, boa tarde.

      Repare que você não tem uma transação única, por isso que ao buscar o objeto de um serviço e salvar em outro ele apresenta essa mensagem.

      Leia a parte sobre esse erro aqui deste post, ele explica direitinho o que está acontecendo.

      Obrigado pela visita.

  4. i am a self-study for java.
    I have view Your tutorials that are very very simple to understand.,
    I have a request for you.

    From the mini book for JPA and the tutorial for JSF , i have noted that into the Entity class and the managedbeans with scoped Session that implements Serializable you put a field :private static final long serialVersionUID = 343L;

    Whi into all class that implements Serializable have a field static final of type Long?
    private static final long serialVersionUID = 343L;
    or
    private static final long serialVersionUID = 1L

    ??????????????

    whi it is static final long ?
    please explique me ……..

    tank you
    Mauro

  5. Thanks for taking the time to write out this tutorial.

    A few suggestions to improve this article.
    – Firstly its a good practice to make sure all entity classes implement the java.io.Serializable interface.

    – When setting the @OneToMany annotation, it is important to talk about the CascadeType options for easier creation/updation of entities. An example of code for insert/update/delete of the entities with and without the CascadeType option will demonstrate the difference in use.

    – The mappedBy value in the cellular class = cellular. What this defines should be explained. This actually refers to the instance variable cellular on the Call object. Since the names are all kept the same most readers will be confused on the name mapping. They may think it refers to the classname when in fact it has nothing to do with the class name.
    I find it useful to actually change the names to demonstrate the actual relationships. So calling cellular, cellularRef on the Call object would make this point more obvious.

    • Hello Kapil,

      1) I just see implementing java.io.Serializable as good practice if you have a multi clustered environment or remove EJB (or anything related to serialization). Do you have any article that talk about that always implementing java.io.Serializable is a good practive?
      2) In this article there is a page that talks about Cascade. [=
      3) Thanks for the mappedBy tip. I will edit it later. [=

      Thanks for passing by! =D

      • When you write code you do not know the target configuration for deployment especially for packaged apps. If you do not implement Serializable and ship your bundle off to a client and they are running a multi clustered environment, guess what will happen?

        • Hello Kapil,

          I do know some seniors Java developers that use JPA and never needed to work with clustered environments.

          Thinking about OO, if a class will never be used in an clustered environment why would it be considered a good practice to add this Interface?

          You thoughts will remain here to be used as an alert to other developers.

          Thanks for passing by! [=

          • Well its good to have differences in opinion :).

            When I write software I can never tell if it is going to be used in a clustered environment or not. All the enterprises i have worked for have had nothing but multi clustered (Cluster of clusters) environments. I rarely write software that would work only on a single node. Unless of course its a quick Proof Of concept.

          • Indeed.

            I always will have the idea that a code that does not follow a good practice will run in every environment.

            In your case, is not good practice but a requirement. Where I live I know a lot of developers that never worked with clustered environment.

            Thanks for passing by.

  6. I outlined the reason why you would implement the interface in my previous comment.
    I can try and explain once again.
    As an example let’s say you are building a Human Resources application that you intend to sell to clients. You are using JPA and do not implement the Serializable interface. One of the clients you sell to is a very large corporation that has a clustered environment. When they buy your application and try to deploy it on their environment it will start throwing serialization errors.
    Does that make sense?

    • Hello Kapil,

      I do not know what is reality of software programming where you live, but I know several developers that never built a software to be sold.

      A developer must understand this: If your software is to be used in a non clustered environment, you will not need to add the interface. If your software is for a clustered environment the interface is not a good practice, but a requirement. That is the difference.

      And if you are building a software to be sold, only by applying the interface will not make your software ready for a clustered environment. A clustered environment is a Requirement that should be specified in the beginning.

      I do respect your opinion, but I do not agree with it. [=

      Thanks for passing by.

  7. Couple of points of interest here :

    1. Usually have the owner of the ManyToMany relationship be the entity that has the less rows when navigating the right side of the join.
    So for e.g. If 1 student can have many courses and many students can have one course we have a many to many relationship between students and courses. In such a model (practically), when navigating from a student record to courses you will have fewer records than from navigating courses to student. In such a case, it makes more sense to define the owner of the relationship be student and not courses. The reason I am saying this when you have a new student in the system its more optimal from a SQL standpoint to navigate from Student to Courses and add the new course. If you had to navigate the other way you will potentially have many more records which means more objects loaded to represent the relationship which means a poorer performing application.

    2. Also in your example you do not need to set both of these
    person.setDog(dogs);
    dog.setPersons(persons);

    just person.setDog(dogs) should work.

    • Hello Kapil,

      1. Sometimes you do not know which entity will have less rows, that I think that the books that I read do not put who should be the owner like you did. But I did like your point of view.

      2. To work like that depends on your implementation. The JPA Pro 2 book makes it clear that passing to only one side the reference the other side will see it.

      Thanks for passing by.

      PS.: Sorry for taking too long to answer you.

    • I do not forgot it, but sometimes an implementation does. =P

      Take the JPA implementation by example, you can have some methods behaving different in each implementation.

      Sometimes The spec says only what a method can or cannot do, allowing it to behave and to have an final destination chosen by it own.

      Thanks for passing by.

  8. Yes and this is perfectly acceptable. You change behavior at deployment time w/o having to recompile code.
    However adding an interface to the codebase will require a recompile. See the difference?
    My point is it does not hurt to put in the interface. It costs nothing but makes your app scale up in a J2EE deployment. Even scaling vertically where the Views & Controller runs in one JVM (Servlets/JSP’s) and the Model (Entities) run in another JVM you will not be able to pass entities to the controller because they do not serialize.

    • 1) If you think by OO, a class have no reason to know a Interface that it will not use it.
      2) A team with developers without experience will not know why the serializable is there (I saw that happing a lot of times), and will start adding it to several other classes thinking that it will solve some error.

      I sorry, but no, I do not see it as good practice. If it is not a requirement, it should not be present.

  9. Hi,
    I have the below scenario. Can I map this relationship in JPA xml if so can you please tell me how to do. Thank you so much.
    We have tables users (userId), organizations(orgId), roles(roleId) and joining tables are users_orgrole_map (userId, orgRoleId) and org_roles_map (orgRoleId, OrgId, roleId). The User Object will have Set of Organizations and Organization Object have set of Roles. (ie User can have different roles in different Organization. UserA belong to OrgA with RoleA permission and UserA belong to OrgB with RoleB permission.)

    • Hello Harishyam,

      Check in this post the page “ManyToMany with extra fields”.

      Thanks for passing by, I am sorry for the late reply. I was very busy this last month.

  10. Hi~ thanks for the great tutorial. It’s very helpful for beginners to understand how composite PK works. I have a question though. How can I create query using only one of the key.

    For instance, I want to find out the cars of a particular CarID.brand. How does it work for your example code? thanks.

    • Hello Dean, how are you?

      You could create the PK key for the query e pass only the value. Something like:
      MyKey key = new MyKey();
      key.setValueA(onlyValueYouHave);
      // do the query

      Thanks for passing by.

  11. Hi, how can i in the example above get all the persons for specific dogId or vice versa using entity manager? thanks

  12. Hi,

    Great post!!
    Could you add the column “cellular_id” to the table “Person”? This makes it clearer. Otherwise, I was scrathcing my head where “cellular_id” is.

    Thanks!

  13. Hello uaihebert,

    Thank you for explaining @TableGenerator. I am a bit confused by how to use initialValue. If I specify an initialValue that is already in use, will the application attempt to overwrite entities in the database? If so, how can I develop an application without having to repeatedly update initialValue when I redeploy the application?

    For example, (1) I deploy the application, and I persist some entities using the web application, (2) I undeploy the application and modify its source code, and (3) I redeploy the application to test my changes. If I don’t update initialValue between steps 1 and 3, will I overwrite entities or otherwise get errors?

    (I will test this myself when I have time, but if you have time I would appreciate your explanation of this.)

    • Hello David, how are you?

      That is a very good question and I do not know the answer without a test too. =/

      Thanks for passing by

Leave a Comment