Estou brigando com esse problema alguns dias já.
Tenho duas classes persistentes conforme descritas abaixo, e mapeadas
para as tabelas correspondentes.
A classe Person possui os atributos “fieldA” e “fieldB” que identificam um registro em ‘persons’ exclusivamente. Mas estou tendo problemas com o identificador (id).
Se eu tenho um objeto Person transiente e quero salvá-lo no banco eu preciso antes verificar se já não existe um registro no banco cujos atributos
"fieldA" e “fieldB” coincidam. No caso de já existir eu preciso apenas atualizar aquele registro baseado na instância do objeto que eu recebo no argumento do método save(Person). Se não existir, um novo Person será salvo no banco de dados.
O comportamento que eu estou observando, com a implementação atual do método save(Person) é: ele atualiza o registro na tabela ‘persons’ corretamente mas replica os filhos (sons) na tabela ‘sons’. Não tenho idéia do que fazer para corrigir o problema.
Seguem as tabelas, mapeamentos (JPA) e a implementação do método save(Person).
[code]TABLE persons (
id INT …,
name VARCHAR(40),
a_field VARCHAR(10),
b_field VARCHAR(10)
)
TABLE sons (
id INT …,
person_id INT REFERENCES persons(id),
name VARCHAR(40)
)[/code]
Mapeamento:
[code]@Entity
@Table(name=“persons”)
class Person {
// …
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
public Long getId() {
return this.id;
}
@Column(name=“name”, length=40, nullable=false)
public String getName() {
return this.name;
}
@Column(name=“a_field”, length=10, nullable=false)
public String getFieldA() {
return this.fieldA;
}
@Column(name=“b_field”, length=10, nullable=false)
public String getFieldB() {
return this.fieldB;
}
@OneToMany(cascade=CascadeType.ALL, mappedBy=“person”)
public Set<Son> getSons() {
return this.sons;
}
}
@Entity
@Table(name=“sons”)
public class Son {
// …
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
public Long getId() {
return this.id;
}
@Column(name=“name”, length=40, nullable=false)
public String getName() {
return this.name;
}
@ManyToOne(cascade=CascadeType.ALL)
@JoinColumn(name=“person_id”)
public Person getPerson() {
return this.person;
}
}[/code]
E a implementação do método save(Person):
[code]public void save(Person person) throws HibernateException {
Session session = …
session.beginTransaction();
Person aperson = (Person)session.createCriteria(Person.class)
.add(Restrictions.eq(“fieldA”, person.getFieldA()))
.add(Restrictions.eq(“fieldB”, person.getFieldB()))
.uniqueResult();
if (aperson != null) {
person.setId(aperson.getId());
session.evict(aperson);
}
session.saveOrUpdate(person);
session.getTransaction().commit();
}[/code]
Na verdade o título deveria ser “Atualização através de um objeto transiente”.