Criei um projeto Java EE (Enterprise Application), com um módulo WEB e outro EJB.
Estou alterando um registro no banco de dados que faz referência a outro.
Quando altero a chave estrangeira, a alteração não é refletida no banco de dados.
Recursos:
Provedor JPA: Eclipse Persistence Services - 2.0.1.v20100213-r6600
EJB: 3.1
DB: MySQL 5
Java: jdk1.6.0_18
Java EE: 6
JSF: 2.0
Contêiner: Glassfish-3.0.1
SO: Linux (Fedora 10)
Tenho duas tabelas:
[code]CREATE TABLE IF NOT EXISTS task (
id bigint(20) NOT NULL auto_increment,
title varchar(255) NOT NULL,
task_status_id bigint(20) NOT NULL,
PRIMARY KEY (id),
KEY FK_task_task_status_id (task_status_id)
);[/code]
[code]CREATE TABLE IF NOT EXISTS task_status (
id bigint(20) NOT NULL auto_increment,
name varchar(255) NOT NULL,
PRIMARY KEY (id)
);[/code]
Representação do banco de dados:
Tabela: task
id | title | task_status_id
1 | Tarefa 01 | 1
Tabela: task_status
id | name
1 | Aprovado
2 | Reprovado
Código exemplo:
@ManagedBean
public class TaskController {
@EJB
private TaskBeanLocal taskBean;
public void edit() {
Task task = taskBean.getTask(1L);
task.setTitle("Titulo alterado");
task.getTaskStatus().setId(2L);
taskBean.update(task);
}
}
No código acima estou alterando o título e o status da tarefa.
O resultado é o seguinte:
[quote]
FINE: UPDATE task SET title = ? WHERE (id = ?)
bind => [Titulo alterado, 1][/quote]
Ou seja, apenas o título é alterado.
Verifiquei dentro do “taskBean.update” e o id do objeto “TaskStatus” está com o valor correto (2), como segue:
[quote]EJB Chamado: TaskBean.update
– Task
---- id: 1
---- title: Titulo alterado
---- TaskStatus
------ iid: 2[/quote]
Apenas consigo alterar o ID do Status da seguinte forma:
Task task = taskBean.getTask(1L);
task.setTitle("Titulo novamente alterado");
TaskStatus taskStatus = new TaskStatus();
taskStatus.setId(2L);
task.setTaskStatus(taskStatus);
taskBean.update(task);
O resultado é o seguinte:
[quote]FINE: UPDATE task SET title = ?, task_status_id = ? WHERE (id = ?)
bind => [Titulo novamente alterado, 2, 1][/quote]
Seguem os outros códigos:
Entidade Task
@Entity
@Table(name="task")
@NamedQueries({
@NamedQuery(name = "Task.findAll", query = "SELECT t FROM Task t")
})
public class Task implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
@Column(name="id")
private Long id;
@Column(name="title", nullable=false)
private String title;
@Column(name="description", nullable=false)
private String description;
@OneToOne
@JoinColumn(name="task_status_id", nullable=false)
private TaskStatus taskStatus = new TaskStatus();
/** Getters and Setters */
@Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Task other = (Task) obj;
if (this.id != other.id && (this.id == null || !this.id.equals(other.id))) {
return false;
}
return true;
}
@Override
public String toString() {
return "core.task.Task[id=" + id + "]";
}
}
Entidade TaskStatus
@Entity
@Table(name="task_status")
@NamedQueries({
@NamedQuery(name = "TaskStatus.findAll", query = "SELECT t FROM TaskStatus t")
})
public class TaskStatus implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE)
@Column(name="id")
private Long id;
@Column(name="name", nullable=false)
private String name;
@OneToOne(mappedBy="taskStatus")
private Task task;
/** Getters and Setters */
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final TaskStatus other = (TaskStatus) obj;
if (this.id != other.id && (this.id == null || !this.id.equals(other.id))) {
return false;
}
return true;
}
@Override
public int hashCode() {
int hash = 7;
hash = 11 * hash + (this.id != null ? this.id.hashCode() : 0);
return hash;
}
@Override
public String toString() {
return "TaskStatus{" + "id=" + id + "name=" + name + "task=" + task + '}';
}
}
EJB TaskBean
@Stateless
public class TaskBean implements TaskBeanRemote, TaskBeanLocal {
@PersistenceContext(unitName="CorePU")
private EntityManager em;
@Override
public void update(Task task) {
System.out.println("EJB Chamado: TaskBean.update");
System.out.println("Task " + task.hashCode());
System.out.println(" id: " + task.getId());
System.out.println(" title: " + task.getTitle());
System.out.println(" TaskStatus " + task.getTaskStatus().hashCode());
System.out.println(" id: " + task.getTaskStatus().getId());
em.merge(task);
}
@Override
public Task getTask(Long id) {
Task task = em.find(Task.class, id);
return task;
}
}
persistence.xml
<?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="CorePU" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/CorePU</jta-data-source>
<properties>
<property name="eclipselink.ddl-generation" value="create-tables"/>
<property name="eclipselink.logging.level" value="FINE"/>
</properties>
</persistence-unit>
</persistence>
Em resumo, quero alterar o status de uma tarefa para o ID 2 (Reprovado), mas apenas o título da tarefa é alterado. Só consigo alterar o status quando crio um novo objeto. Essa ultima solução não é adequada, pois utilizo o JSF (versão 2.0) para popular os atributos dos meus objetos.
Alguém pode me ajudar solucionar esse problema?
Porque o primeiro código não funciona?
Agradeço desde já.
Henrique