EclipseLink – 05 – Mapping the Primary Key

Merhaba Arkadaslar
Bu bolumde primary key konusunu inceleyecegiz. Her Entity’in bir unique/tekil primary key degeri olmalidir. Entity tanimlamak icin gerekli olan minimum annotation @Entity ve @Id di. Burada @Id annotation ile birlikte kullanacagimiz primary key generator yaklasimlarini inceleyecegiz.

Bu bolumde inceleyecegimiz annotation’lar

  • @GeneratedValue
    • GenerationType.AUTO
    • GenerationType.TABLE
    • GenerationType.SEQUENCE
    • GenerationType.IDENTITY
  • @TableGenerator
  • @SequenceGenerator

Bu bolumde MySQL ile birlikte Oracle da kullanacagiz. Oncelikle pom.xml dosyamiza Oracle a baglanabilmek icin gerekli jar dosyasini ekleyelim. Bu jar dosyasi maven repositoryde yer almamaktadir , bunun icin ilgili repositoryde pom.xml dosyasina ekleyelim.

pom.xml

....
	<repositories>
		<repository>
			<id>codelds</id>
			<url>https://code.lds.org/nexus/content/groups/main-repo</url>
		</repository>
	</repositories>

	<dependencies>
	.....
		<dependency>
			<groupId>com.oracle</groupId>
			<artifactId>ojdbc6</artifactId>
			<version>11.2.0.3</version>
		</dependency>

	</dependencies>
...

MySQL ve Oracle’i donusumlu olarak test edecegiz. Bunun icin persistence.xml dosyamiza property tanimlarini ekleyelim. Tabi donusumlu kullanacagimiz icin yorum satiri seklinde olsun. Bir diger konu olarak user , password gibi bilgileri kendinize uygun sekilde ayarlayin. Varsayilan olan 1521 portunu 1520 olarak kullaniyorum. Bu kisma da dikkat edin.

	<property name="javax.persistence.jdbc.driver" value="oracle.jdbc.driver.OracleDriver" />
	<property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:@localhost:1520:xe" />
	<property name="javax.persistence.jdbc.user" value="Levent" />
	<property name="javax.persistence.jdbc.password" value="123456" />
	<property name="eclipselink.ddl-generation" value="drop-and-create-tables" />

Primary Key Types

  • Primitive Java types : byte, int , short , long, char
  • Wrapper : Byte , Integer , Short , Long , Character
  • String : java.lang.String
  • Large Numeric Types : java.math.BigInteger
  • Temporal Types : java.util.Date , java.sql.Date

Bu tiplerin disinda float , double , Float , Double , java.math.BigDecimal gibi tipler de kullanilabilir fakat bu tiplerin kullanilmasi tutarsizlik nedeniyle onerilmez.

Identifier Generation

Identifier/Primary Key uretmek/generate icin @GeneratedValue annotation kullanilir. @GeneratedValue kullanildiginda her Entity icin otomatik olarak secilen stratejiye gore primary key verilir.
@GeneratedValue ile birlikte kullanacagimiz stratejiler/yaklasimlar sunlardir;

  • AUTO
  • TABLE
  • SEQUENCE
  • IDENTITY
package javax.persistence;

public enum GenerationType { 

    TABLE, 

    SEQUENCE, 

    IDENTITY, 

    AUTO
}

AUTO

GenerationType.AUTO secildiginde Persistence provider kullanilan database/veritabanina gore uygun bir strateji/yaklasim secer.
Ornegin MySQL icin Sequence adinda bir tablo olusur ve bu tablodaki SEQ_GEN degerinden yararlanilir. Dikkat edelim sequence adinda bir sequence degil bir tablo olusur.
MySQL de sequence kavrami yoktur bunun yerine AUTO_INCREMENT sistemi vardir.

A.1.6: Does MySQL 5.0 have Sequences?

Employee10.java
Burada dikkat edecek olursak yapilandiricimiz id parametresi almiyor.

package _10.idgeneration.auto.model;

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

@Entity
public class Employee10 {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;
    private String name;
    private String surname;
    private int salary;

    public Employee10() {
        super();
    }

    public Employee10(String name, String surname, int salary) {
        super();
        this.name = name;
        this.surname = surname;
        this.salary = salary;
    }

    // getters and setters
    // toString

}

EmployeeTest.java
createEmployee metodumuzda kendimiz id degeri arguman olarak vermiyoruz. Id generate/uretme islemini Persistence provider/EclipseLink e birakiyoruz.

package _10.idgeneration.auto.test;

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

import _10.idgeneration.auto.dao.EmployeeDAO;
import _10.idgeneration.auto.dao.EmployeeDAOImpl;
import _10.idgeneration.auto.model.Employee10;

public class EmployeeTest {

	public static void main(String[] args) {

		EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("EmployeePersistenceUnit");
		EntityManager entityManager = entityManagerFactory.createEntityManager();
		EntityTransaction entityTransaction = entityManager.getTransaction();

		EmployeeDAO employeeService = new EmployeeDAOImpl(entityManager);

		entityTransaction.begin();
		Employee10 employee = employeeService.insertEmployee("Levent", "Erguder", 1000);
		Employee10 Employee2 = employeeService.insertEmployee("James", "Gosling", 10000);
		Employee10 employee3 = employeeService.insertEmployee("Joshua", "Bloch", 10000);
		entityTransaction.commit();

		System.out.println("Persisted :" + employee);
		System.out.println("Persisted :" + Employee2);
		System.out.println("Persisted :" + employee3);

		entityManager.close();
		entityManagerFactory.close();

	}
}

sequence table mysql

Oracle icin test edersek benzer sekilde “Sequence” adinda tablomuz olusacaktir.

sequence table oracle

Table

Identifier/Primary key uretmek/olusturmak icin kullanabilecek en esnek/flexible , tasinabilir/portable yaklasim TABLE yaklasimidir.

Bir tabloda , varsayilan olarak Sequence adindaki tabloda  SEQ_NAME ve SEQ_COUNT olmak uzere 2 kolon/column olusur. SEQ_NAME kolonundaki degere karsilik SEQ_COUNT ta sayisal bir deger tanimlanir. Table yaklasimi kullanildiginda sequence mantigi bu tablodaki kayit uzerinden gerceklestirilir.

Employee11.java

package _11.idgeneration.table.model;

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

@Entity
public class Employee11 {

	@Id
	@GeneratedValue(strategy = GenerationType.TABLE)
	private int id;
	private String name;postgres
	private String surname;
	private int salary;

	public Employee11() {
		super();
	}

	// id degerini kendimiz vermiyoruz!
	public Employee11(String name, String surname, int salary) {
		super();
		this.name = name;
		this.surname = surname;
		this.salary = salary;
	}

	//getters and setters
        //toString

}

Bu durumda sequence tablosunda SEQ_GEN_TABLE degeri olusacaktir. Varsayilan olarak bu kayit kullanilir. Birden fazla sinif icin TABLE yaklasimi kullanildiginda tum siniflarin Entity’leri icin SEQ_GEN_TABLE kullanilacaktir.

seq_gen_table

seq_gen_table oracle

Peki hepsinin SEQ_GEN_TABLE degerini ortak kullanmasini istemezsek bu durumda ne yapabiliriz ? Bunun icin @TableGenerator annotation’i kullanabiliriz.

Varsayilan olarak kullanilan SEQ_GEN_TABLE yerine EMP_GEN sequence-value ciftini kullanabiliriz.

	@TableGenerator(name="EMP_GEN")
	@Id 
	@GeneratedValue(generator="EMP_GEN")	
	private int id;

TableGenerator

@TableGenerator da table attribute kullanarak yeni bir tablo olusturabiliriz. Tablodaki SEQ_NAME ve SEQ_COUNT column isimlerini degistirebiliriz (pkColumnName , valueColumnName) , initialValue ve allocationSize degerlerini degistirebiliriz.

initialValue varsayilan olarak 0’dir ve bunun anlami henuz bir identifier/primary key olusturulmadi demektir ,allocationSize 50 dir.

Her kayitta kullanmak icin gerekli olan primary key degerini tablodan tek tek almak yerine allocationSize kullanilir. Hafizaya bu allocate edilen block alinir ve gerekli oldugunda bu hafizaya alinan blocktaki degerler kullanilir. Block tukendiginde yeni bir allocationSize kadar deger alinir.

Ornegimizde 3 tane kayit tabloya eklenmektedir , bu 3 kayit icin 1 kez tabloya gitmek yeterli olacaktir. Eger 50den fazla kayit eklememiz gerekse bu durumda 2. defa tabloya gidip allocationSize kadar block deger hafizaya alinacaktir. Boylelikle her Entity’in veritabanina kaydedilmesi icin gerekli olan primary key degeri icin tek tek tabloya gidilmez.

@TableGenerator(name="EMP_GEN_DETAILED",
	table="ID_GEN",
	pkColumnName="ID_GEN_NAME",
	valueColumnName="ID_GEN_COUNT",
	initialValue=200,
	//varsayilan olarak initial 0 dir.
	//varsayilan olarak allocationSize 50dir.
	allocationSize=10)
	@Id
	@GeneratedValue(generator="EMP_GEN_DETAILED")
	//##### example 3 end
	private int id;

TableGenerator oracle

Employee11.java

package _11.idgeneration.table.model;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
//import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.TableGenerator;

@Entity
public class Employee11 {
	
	//##### example 1 start
	
	//@Id
	//@GeneratedValue(strategy = GenerationType.TABLE)
	//MySQL de varsayilan olarak "sequence" tablosu kullanilir.
	//varsayilan olarak SEQ_NAME column degeri -> SEQ_GEN_TABLE
	
	//##### example 1 end
	
	//##### example 2 start
	
	//TableGenerator annotation kullanildiginda SEQ_NAME degeri icin SEQ_GEN_TABLE override edilir.
	// SEQ_GEN_TABLE yerine EMP_GEN degeri kullanilir.
	//@TableGenerator(name="EMP_GEN")
	//@Id 
	//@GeneratedValue(generator="EMP_GEN")	
	//##### example2 end
	
	//##### example 3 start
	//@TableGenerator da table attribute kullanarak yeni bir tablo olusturabiliriz.
	//tablomuzun adi ID_GEN
	//SEQ_NAME ve SEQ_COUNT olan column isimleri ID_GEN_NAME ve ID_GEN_COUNT olsun.
	//ID_GEN_NAME degeri -> EMP_GEN
	@TableGenerator(name="EMP_GEN_DETAILED",
	table="ID_GEN",
	pkColumnName="ID_GEN_NAME",
	valueColumnName="ID_GEN_COUNT",
	initialValue=200,
	//varsayilan olarak initial 0 dir.
	//varsayilan olarak allocationSize 50dir.
	allocationSize=10)
	@Id
	@GeneratedValue(generator="EMP_GEN_DETAILED")
	//##### example 3 end
	private int id;
	private String name;
	private String surname;
	private int salary;

	public Employee11() {
		super();
	}

	// id degerini kendimiz vermiyoruz!
	public Employee11(String name, String surname, int salary) {
		super();
		this.name = name;
		this.surname = surname;
		this.salary = salary;
	}

	//getter setter
}

SEQUENCE

Bir cok veritabaninda sequence tanimlanabilir. Bu sequence’ler identifier/primary key uretmek icin kullanilabilir. MySQL Sequence objesi desteklemezken , Oracle Sequence objesi destekler.

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private int id;

Sequence konusunda daha fazla bilgi icin ;
Oracle Ders 9 – Sequence
Sequence ismi belirtilmediginde varsayilan sequence objesi kullanilir. @SequenceGenerator annotation’i kullanabiliriz.

create sequence emp_sequence;

Employee12.java

package _12.idgeneration.sequence.model;

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

@Entity
public class Employee12 {

//	@Id
//	@GeneratedValue(strategy = GenerationType.SEQUENCE)
	
	@SequenceGenerator(name="Emp_Seq_Gen", sequenceName="EMP_SEQUENCE", initialValue=20, allocationSize=30)
	@Id @GeneratedValue(generator="Emp_Seq_Gen" , strategy= GenerationType.SEQUENCE)
	private int id;
	private String name;
	private String surname;
	private int salary;

	public Employee12() {
		super();
	}

	// id degerini kendimiz vermiyoruz!
	public Employee12(String name, String surname, int salary) {
		super();
		this.name = name;
		this.surname = surname;
		this.salary = salary;
	}

	//getter setter

}

sequence generator

IDENTITY

Bazi veritabanlari autonumber column destekler , bir nevi sequence gibi dusunebiliriz.Genel olarak primary key uretimi konusunda IDENTITY yaklasimi daha verimsizdir.
Sequence mantigindan farkli olarak allocation desteklenmez.

IDENTITY yaklasiminda bir generator annotation yoktur.

Employee13.java

package _13.idgeneration.identity.model;

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

@Entity
public class Employee13 {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
	private int id;
	private String name;
	private String surname;
	private int salary;

	public Employee13() {
		super();
	}

	// id degerini kendimiz vermiyoruz!
	public Employee13(String name, String surname, int salary) {
		super();
		this.name = name;
		this.surname = surname;
		this.salary = salary;
	}

	//getter setter

}

Oracle icin test edecek olursak SEQ_GEN_IDENTITY adinda bir sequence olusur.

persistence.xml son hali;

persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence 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://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
version="2.1">
	<persistence-unit name="EmployeePersistenceUnit"
		transaction-type="RESOURCE_LOCAL">
		<class>_01.hello.eclipselink.model.Employee</class>
		<class>_02.field.access.model.Employee2</class>
		<class>_03.property.access.model.Employee3</class>
		<class>_04.mixed.access.model.Employee4</class>
		<class>_05.mapping.table.model.Employee5</class>
		<class>_06.mapping.column.model.Employee6</class>
		<class>_07.mapping.enumerated.model.Employee7</class>
		<class>_08.mapping.temporal.model.Employee8</class>
		<class>_09.mapping.lob.model.Employee9</class>
		<class>_10.idgeneration.auto.model.Employee10</class>
		<class>_11.idgeneration.table.model.Employee11</class>
		<class>_12.idgeneration.sequence.model.Employee12</class>
		<class>_13.idgeneration.identity.model.Employee13</class>
		<properties>	
						
			<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
			<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/jpa.schema" />
			<property name="javax.persistence.jdbc.user" value="root" />
			<property name="javax.persistence.jdbc.password" value="" />
			 <!-- 				
			<property name="javax.persistence.jdbc.driver" value="oracle.jdbc.driver.OracleDriver" />
			<property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:@localhost:1520:xe" />
			<property name="javax.persistence.jdbc.user" value="Levent" />
			<property name="javax.persistence.jdbc.password" value="123456" />
			
			-->
			<property name="eclipselink.ddl-generation" value="drop-and-create-tables" />
			<property name="eclipselink.logging.level" value="OFF" />
		</properties>
	</persistence-unit>
</persistence>

Yazimi burada sonlandiriyorum.

Herkese Bol Javali Gunler dilerim.
Be an oracle man , import java.*;
Levent Erguder
OCP, Java SE 6 Programmer
OCE, Java EE 6 Web Component Developer

Print Friendly, PDF & Email

Leave a Reply

Your email address will not be published. Required fields are marked *