JPA Uma tabela por herança

EXISTE UMA NOVA VERSÃO DESSE POST.
CLICK AQUI: http://uaihebert.com/?p=1622&page=13

Olá, tudo bem?

Vamos falar hoje sobre como salvar nas tabelas que envolvem herança. Vamos começar pelo modo “Single Table per Class Hierarchy” (Uma tabela para toda herança).

Os outros assuntos já tratados sobre JPA: Ordernando listas e utilizando Map como atributo mapeado, @ManyToMany Unidirecional e Bidirecional, JPA @OneToMany e @ManyToOne Unidirecional e Bidirecional, @OneToOne Unidirecional e Bidirecional, Mapeando Duas Tabelas em uma Classe, Mapeando Datas (Date) e Enum, Chave Primária Composta, SequenceGenerator, TableGenerator – Chave Primária Simples, Auto Create Schema Script com: Ant, Hibernate 3 e JPA 2, Tutorial Hibernate 3 com JPA 2.

Ao final do post de hoje você irá encontrar o código fonte para download.

Vamos utilizar um sistema de carros onde teremos a classe principal e outras duas classes herdando da classe pai. Vejamos nosso código inicial:

package com.model;

public abstract class Car {
	private int id;
	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}
}
package com.model;

public class Beetle extends Car {
	private int gasCapacity;

	public void talk(){
		System.out.println("Herbie!");
	}

	public int getGasCapacity() {
		return gasCapacity;
	}

	public void setGasCapacity(int gasCapacity) {
		this.gasCapacity = gasCapacity;
	}

}
package com.model;

public class Ferrari extends Car {
	private int model;

	// The newest new models will fly... some day! =P
	public void fly() {

	}

	public int getModel() {
		return model;
	}

	public void setModel(int model) {
		this.model = model;
	}
}

Temos um modelo bem simples onde queremos persistir todas as informações em uma tabela. No exemplo de hoje irei utilizar o Postgres como banco de dados para exibir no final como os dados ficarão gravados no banco de dados.

Coloquemos as anotações JPA para que a herança seja persistida:

package com.model;

import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table;

@Entity
@Table(name="CAR")
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="FROM_CLASS", discriminatorType=DiscriminatorType.STRING)
public abstract class Car {
	@Id
	@GeneratedValue(strategy=GenerationType.AUTO)
	private int id;
	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}
}
package com.model;

import javax.persistence.Entity;

@Entity
public class Beetle extends Car {
	private int gasCapacity;

	public void talk(){
		System.out.println("Herbie!");
	}

	public int getGasCapacity() {
		return gasCapacity;
	}

	public void setGasCapacity(int gasCapacity) {
		this.gasCapacity = gasCapacity;
	}
}
package com.model;

import javax.persistence.Entity;

@Entity
public class Ferrari extends Car {
	private int model;

	// The newest new models will fly... some day! =P
	public void fly() {

	}

	public int getModel() {
		return model;
	}

	public void setModel(int model) {
		this.model = model;
	}
}

Algumas explicações sobre o código acima:

  • A anotação “@Inheritance” indica ao JPA qual o tipo de herança iremos utilizar ao persistir as informações.
  • A anotação “@DiscriminatorColumn” é uma coluna onde ficará armazenado um valor descrevendo a qual classe pertence aquela linha.

Com a classe abaixo, vamos inserir dados no banco de dados e ver como ficou.

package com;

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

import com.model.Beetle;
import com.model.Ferrari;

public class Main {

	public static void main(String[] args) {
		EntityManagerFactory emf = Persistence.createEntityManagerFactory("Database");
		EntityManager em = emf.createEntityManager();

		em.getTransaction().begin();

		try {
			Ferrari ferrari = new Ferrari();
			ferrari.setModel(455);
			ferrari.setName("WWJD");

			Beetle beetle = new Beetle();
			beetle.setGasCapacity(46);
			beetle.setName("Heeerbie");

			em.persist(ferrari);
			em.persist(beetle);
		} catch (Exception ex) {
			ex.printStackTrace();
		} finally {
			em.getTransaction().commit();
			emf.close();
		}

		System.out.println("It is over");
	}

}


Repare que na tabela apareceu uma coluna chamada “from_class” que indica à qual classe pertence à respectiva linha.

E para finalizar, como faríamos para alterar o valor salvo na no coluna? E se quisemos mudar o nome de como o valor da classe será salvo? Ao invés de Ferrari for CAR_FERRARI, como faríamos?

Basta editar a classe e deixar conforme o código abaixo:

package com.model;

import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;

@Entity
@DiscriminatorValue(value="CAR_BEETLE")
public class Beetle extends Car {
	private int gasCapacity;

	public void talk(){
		System.out.println("Herbie!");
	}

	public int getGasCapacity() {
		return gasCapacity;
	}

	public void setGasCapacity(int gasCapacity) {
		this.gasCapacity = gasCapacity;
	}
}
package com.model;

import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;

@Entity
@DiscriminatorValue(value="CAR_FERRARI")
public class Ferrari extends Car {
	private int model;

	// The newest new models will fly... some day! =P
	public void fly() {

	}

	public int getModel() {
		return model;
	}

	public void setModel(int model) {
		this.model = model;
	}
}

Execute a classe Main novamente e veja o resultado:


Note que as linhas 1 e 2 estão com os valores antigos. As linhas 3 e 4 já constam os valores da nova anotação inserida “@DiscriminatorValue”.

Vamos falar agora dos contras e prós dessa abordagem:

  • Prós: O desempenho é maior e melhor, pois o JPA não irá necessitar fazer diversos Joins para ter as informações de todas as classes. Para quem está começando a trabalhar com esse tipo de persistência é mais fácil de adaptar e coletar informações no banco de dados.
  • Contras: As subclasses não poderão conter campos “não nullos”. Se a classe Beetle tivesse um atributo não nulo ao se salvar um objeto Ferrari o banco de dados levantaria uma Exception.

Clique aqui para fazer o download do código de hoje. Esteja atento ao fato que para o código rodar você precisará ter o Postgres instalado e com um “database” chamado “SingleTable”. E não esqueça também de configurar o usuário e senha. ^o^

Espero que o post de hoje possa te ajudar.

Qualquer dúvida/colocação basta postar.

Até mais! o_

2 thoughts on “JPA Uma tabela por herança

Leave a Comment