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

Wednesday, 16 June 2010

Specificarea relaţiilor dintre entităţile JPA

Există patru tipuri de relaţii între entităţile JPA, şi anume:

Relaţii ``unul cu unul'' (One-to-One)
Relaţii ``unul cu mai mulţi''(One-to-Many)
Relaţii ``mai mulţi cu unul''(Many-to-One)
Relaţii ``mai mulţi cu mai mulţi'' (Many-to-Many)

O relaţie poate fi unidirecţională sau bidirecţională. Într-o relaţie unidirecţională, una şi numai una dintre entităţi conţine un câmp care se referă la cealaltă entitate. Într-o relaţie bidirecţională, fiecare dintre entităţi conţine un câmp care se referă la cealaltă. Direcţia relaţiei dintre două entităţi determină posibilitatea unei interogări (query) de a naviga de la o entitate la cealaltă. Implementarea relaţiilor în contextul de persistenţă, care determină modul în care se fac actualizările în baza de date, se realizează prin adnotarea câmpurilor care se referă la entităţile relaţionate, în funcţie de tipul relaţiei, cu @OneToOne, @ManyToOne@OneToMany, @ManyToMany, @JoinColumn, @JoinTable, etc.

Exemple

@Entity
@Table(name="CURSURI")

@NamedQueries({
@NamedQuery(name="Cursuri.numeTitular",
    query="select o.profesor from Cursuri o " +
          "where o.cursId = :param"),
@NamedQuery(name="Cursuri.studentiInscrisi",
        query="select o.studenti from Cursuri o " +
          "where o.cursId = :param")
})

public class Cursuri implements Serializable{

@Id
@Column(name="CURSID", nullable=false)
private int cursId;

@Column(name="NUME")
private String nume;

//mai multe cursuri la un profesor

@ManyToOne
@JoinColumn(name="PROFESORID",referencedColumnName="PROFESORID")
private Profesori profesor;


//mai multe cursuri la un student, mai multi studenti la un curs
@ManyToMany
@JoinTable(name="STUD_CURS",
       joinColumns=
           @JoinColumn(name="CURSID",referencedColumnName="CURSID"),
       inverseJoinColumns=
           @JoinColumn(name="STUDENTID",referencedColumnName="STUDENTID"))
//name=numele coloanei din tabela STUD_CURS (tabela de join)
//referencedColumnName=numele coloanelor din tabelele CURSURI, respectiv STUDENTI
private List studenti;

...

@Entity
@Table(name="STUDENTI")

@NamedQuery(name="Studenti.note",
    query="select o.note from Studenti o " +
          "where o.studentId = :param")

public class Studenti implements Serializable{

@Id
@Column(name="STUDENTID", nullable=false)
private int studentId;

@Column(name="NUME")
private String nume;

@Column(name="PRENUME")
private String prenume;

@Column(name="EMAIL")
private String email;

@OneToOne
@JoinColumn(name="STUDENTID",referencedColumnName="STUDENTID")
private Note note;

...

@Stateless(name="FatadaCursuri")
public class FatadaCursuriBean implements FatadaCursuri{

@PersistenceContext(unitName="CelestePersistUnit")
EntityManager em;

public String cautaTitular(int id){

Profesori titular = (Profesori)em.createNamedQuery("Cursuri.numeTitular").
            setParameter("param",id).getSingleResult();

return titular.citesteNume();

}

public List cautaStudenti(int idCurs){

List listaStudenti = (List)em.createNamedQuery("Cursuri.studentiInscrisi").setParameter("param",idCurs).getResultList();
return listaStudenti;

}

public Note cautaNote(int idStud){

Note note = (Note)em.createNamedQuery("Studenti.note").
            setParameter("param",idStud).getSingleResult();

return note;

}

public List getGradesforOneStudent(int idStud){
List note = (List)em.createNamedQuery("Grades.forOneStudent").
            setParameter("param",idStud).getResultList();

return note;
}

}

Monday, 31 May 2010

Querying the database with JPA

When working with entity beans you can retrieve records from the database using Java Persistence Query Language (JPQL), a declarative language similar to SQL but which works with Java objects rather than relational tables. Both dynamic and static queries can be defined with JPQL. Static queries (named queries) are defined in a JPA entity nested within a @NamedQuery annotation. Dynamic queries are defined directly within an application's business logic. The EntityManager interface provides the methods createQuery and createNamedQuery used to create dynamic, respectively static queries.
The Java EE 6 Tutorial presents JPQL in detail. (http://java.sun.com/javaee/6/docs/tutorial/doc/bnbrg.html)

Wednesday, 19 May 2010

Composite Primary Keys for JPA Entities

When the primary key of a JPA entity is composed from more than one attribute it is necessary to define a class corresponding to the primary key.

The JPA entity will use the @IdClass annotation to specify the name of the class corresponding to the composite primary key.

In the class corresponding to the JPA entity, the attributes included in the primary key will be marked with the @Id annotation.

Example using a compound primary key in JPA

1.Create and populate a table to be used by the example.

ij> CREATE TABLE Grades(
> studentID INTEGER NOT NULL,
> cursID INTEGER NOT NULL,
> semestrul1 INTEGER,
> semestrul2 INTEGER,
> laborator INTEGER,
> CONSTRAINT pk_SidCid PRIMARY KEY(studentID,cursID));
0 rows inserted/updated/deleted
...
ij> INSERT INTO Grades VALUES
> (1,1,9,10,10);
1 row inserted/updated/deleted
...
 ij> SELECT * FROM Grades;
STUDENTID  |CURSID     |SEMESTRUL1 |SEMESTRUL2 |LABORATOR
-----------------------------------------------------------
1          |1          |9          |10         |10
2          |1          |8          |7           |8
3          |1          |10         |10        |10
28 rows selected

2.Define the JPA entity

import javax.persistence.Entity;
import javax.persistence.Table;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.Column;
import javax.persistence.NamedQuery;
import java.io.Serializable;

@Entity
@Table(name="GRADES")
@IdClass(GradesPK.class)
@NamedQuery(name="Grades.forOneStudent",
query="select o from Grades o where o.studentId=:param")

public class Grades implements Serializable{

@Id
@Column(name="STUDENTID", nullable=false)
private int studentId;

@Id
@Column(name="CURSID", nullable=false)
private int cursId;

@Column(name="SEMESTRUL1")
private int semestrul1;

...
}

3.Define the class corresponding to the primary key.

Make sure that the names and types of the fields are the same with those in the entity bean!

import java.io.Serializable;

public class GradesPK implements Serializable{

public int studentId;
public int cursId;

public GradesPK(){
//constructor public fara parametri
}

public GradesPK(int studentId, int cursId){
this.studentId=studentId;
this.cursId=cursId;
}

public int hashCode(){
return super.hashCode();
}

public boolean equals(Object other){

if(!(other instanceof GradesPK)){
return false;}

GradesPK celalalt = (GradesPK)other;

return(celalalt.studentId==studentId
       &&
      celalalt.cursId==cursId);
}
}

4.Define a method in a session bean to use for testing a query.

public List getGradesforOneStudent(int idStud){
List note = (List)em.createNamedQuery("Grades.forOneStudent").
            setParameter("param",idStud).getResultList();

return note;
}


5.Write a test client to call the method.
 
import javax.naming.InitialContext;
import java.util.List;
import java.util.ListIterator;
...

public class Client1{
public static void main(String[] args) throws Exception
{
    InitialContext ctx = new InitialContext();
    FatadaCursuri beanInstance = (FatadaCursuri)
                                      ctx.lookup(FatadaCursuri.class.getName());

    List grades = beanInstance.getGradesforOneStudent(2);
    ListIterator listIterator2 = grades.listIterator();
    System.out.println("Notele studentului cu studentId=2");
    while(listIterator2.hasNext()){
    Grades linie = (Grades)listIterator2.next();
    System.out.print("ID Curs:"+linie.citesteCursId());
    System.out.print(" Nota 1:"+linie.citesteSemestrul1());
    System.out.print(" Nota 2:"+linie.citesteSemestrul2());
    System.out.println(" Nota lab.:"+linie.citesteLaborator());   
    }
}
}

Friday, 23 April 2010

Entităţi JPA în Java EE 6

Clasa corespunzătoare unei tabele relaţionale

Java EE foloseşte standardul JPA(Java Persistence API) pentru realizarea corespondenţei dintre obiecte Java şi tabele ale unei baze de date relaţionale. Între aplicaţie, care foloseşte modelul bazat pe obiecte, şi schema bazei de date există în Java EE un nivel numit ``de persistenţă'', care izolează programatorul de problemele specifice bazei de date (e.g. gestiunea tranzacţiilor). O tabelă dintr-o bază de date relaţională este reprezentată în program printr-o entitate JPA, o clasă Java marcată cu adnotarea @Entity.

O instanţă a unei entităţi JPA corespunde unei linii din tabela asociată.

Corespondenţa dintre o entitate JPA şi o tabelă din baza de date se realizează folosind adnotări în clasa Java care reprezintă entitatea JPA. Astfel, de exemplu, @Table specifică numele tabelei cu care entitatea este asociată, @Column desemnează numele coloanei din tabelă cu care este asociat câmpul marcat al entităţii JPA, @Id marchează un câmp al entităţii care corespunde unei chei primare in tabela asociată.

Mai jos se găseşte definiţia clasei Student, entitatea JPA corespunzătoare unei tabele STUDENT.

package doi;

import javax.persistence.Entity;
import javax.persistence.Table;
import javax.persistence.Id;
import javax.persistence.Column;
import java.io.Serializable;

@Entity
@Table(name="STUDENT")

public class Student implements Serializable{

@Id
@Column(name="STUDENTID", nullable=false)
private int studentId;

@Column(name="NUME")
private String nume;

@Column(name="PRENUME")
private String prenume;

@Column(name="EMAIL")
private String email;

public Student(){
}

public long citesteStudentId(){
return studentId;
}
public void scrieStudentId(int i){
studentId=i;
}
public String citesteNume(){
return nume;
}
public void scrieNume(String n){
nume=n;
}
public String citestePrenume(){
return prenume;
}
public void scriePrenume(String p){
prenume=p;
}
public String citesteEmail(){
return email;
}
public void scrieEmail(String e){
email=e;
}
}

Componenta de tip sesiune, faţada componentei de tip entitate 

Găsirea, actualizarea, crearea şi ştergerea obiectelor asociate cu linii dintr-o tabelă relaţională (găsirea, actualizarea, crearea şi ştergerea entităţilor JPA) se face prin intermediul unor metode specificate de interfaţa EntityManager, care face parte din standardul JPA.

Pentru a obţine o instanţă de tip EntityManager se foloseşte adnotarea @PersistenceContext pentru a injecta gestionarul de entităţi JPA în componenta care operează cu entităţi JPA.

Accesul la o componentă de tip entitate este implementat prin intermediul unei componente de tip sesiune. Definim în continuare interfaţa şi clasa corespunzătoare componentei CautaStudent, o componentă de tip sesiune, fără stare, care defineşte metoda cauta(int id). Rezultatul metodei cauta reprezintă numele studentului cu id-ul dat ca argument, obţinut prin folosirea metodei find() a gestionarului de entităţi em. La apelul metodei find(), gestionarul de entităţi extrage înregistrarea căutată din baza de date şi instanţiază cu valorile obţinute un obiect de tipul corespunzător (în exemplul nostru de tipul Student).

Definiţia interfeţei

package doi;

import javax.ejb.Remote;
import doi.Student;

@Remote
public interface CautaStudent{
public String cauta(int id);
}

Definiţia clasei

package doi;

import javax.ejb.Stateless;
import javax.annotation.Resource;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceUnit;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;

import doi.Student;

@Stateless(name="CautaStudent")
public class CautaStudentBean implements CautaStudent{

@PersistenceContext(unitName="StudentPersistUnit")
EntityManager em;

public String cauta(int id){
Student s = em.find(Student.class,id);
return s.citesteNume();
}
}

Compilaţi entitatea JPA, interfaţa şi clasa corespunzătoare componentei de tip sesiune, folosind următoarele comenzi:

C:\EJB>set CLASSPATH=.;C:\glassfishv3\glassfish\lib\javaee.jar

C:\EJB>javac -d . doi/Student.java

C:\EJB>javac -d . doi/CautaStudent.java

C:\EJB>javac -d . doi/CautaStudentBean.java

Definirea unităţii de persistenţă

O unitate de persistenţă defineşte mulţimea tuturor entităţilor JPA dintr-o aplicaţie administrate de instanţe de tipul EntityManager şi specifică numele global JNDI al sursei de date corespunzătoare. Unităţile de persistenţă sunt definite în fişierul de configurare persistence.xml, care trebuie să se găsească în directorul META-INF al unei arhive EJB-JAR.

Pentru exemplul considerat am creat în directorul C:\EJB\META-INF fişierul persistence.xml redat mai jos, care specifică numele sursei de date folosite de către containerul EJB (jdbc/student) şi numele clasei de persistenţă gestionată de EntityManager (doi.Student).

<persistence>
<persistence-unit name="StudentPersistUnit">
<description>
Prima unitate de persistenta.
Administreaza date referitoare la studenti.
</description>
<jta-data-source>jdbc/student</jta-data-source>
<class>doi.Student</class>
</persistence-unit>
</persistence>

Construiţi arhiva MyStudentApp.jar folosind următoarea comandă:

C:\EJB> jar cvf MyStudentApp.jar doi/CautaStudent.* doi/CautaStudentBean.* doi/Student.* META-INF/persistence.xml

Încărcaţi arhiva MyStudentApp.jar pe serverul de aplicaţii, folosind consola grafică de administrare şi specificând tipul arhivei ca fiind EJB Jar.

Un exemplu de client

package clienti;

import doi.CautaStudent;
import javax.naming.InitialContext;
import doi.Student;

public class EntityBeanStudentClient{
public static void main(String[] args) throws Exception
{
InitialContext ctx = new InitialContext();
CautaStudent beanInstance = (CautaStudent)
                            ctx.lookup(CautaStudent.class.getName());
String myName=beanInstance.cauta(777);
System.out.println("Hi, "
                   + myName + "!");
}
}

Compilaţi şi executaţi programul client folosind următoarele comenzi:

C:\EJB>javac -d . clienti/EntityBeanStudentClient.java

C:\EJB>java -classpath C:\glassfishv3\glassfish\lib\appserv-rt.jar;C:\glassfishv3\glassfish\lib\javaee.jar;. clienti.EntityBeanStudentClient