Объединить JPA Entity, используя EntityHome из JBoss Seam
Я пытаюсь обновить сущность, используя JBoss Seam и JPA, но сталкиваюсь с очень распространенной проблемой Detached Entity. Я объясню лучше.
У меня есть две простые сущности, которые связаны между собой. Эти отношения отображаются с аннотациями. Взглянуть:
@Entity
@Table(name = "RATEIO", uniqueConstraints = { @UniqueConstraint(columnNames = { "cd_projeto", "cd_tarefa", "cd_colaborador", "dt_rateio_inicial",
"dt_rateio_final" }) })
@Audited
public class Rateio implements java.io.Serializable {
private static final long serialVersionUID = 1564844894403478898L;
private Long cdRateio;
private Colaborador colaborador;
private Tarefa tarefa;
private Projeto projeto;
private Date dtRateioInicial;
private Date dtRateioFinal;
private boolean flagAtividade;
private TipoRateio tipo;
private List<DetalheRateio> detalheRateios = new ArrayList<DetalheRateio>(0);
public Rateio() {
}
public Rateio(Long cdRateio, Colaborador colaborador, Projeto projeto, Date dtRateioInicial, Date dtRateioFinal) {
this.cdRateio = cdRateio;
this.colaborador = colaborador;
this.projeto = projeto;
this.dtRateioInicial = dtRateioInicial;
this.dtRateioFinal = dtRateioFinal;
}
public Rateio(Long cdRateio, Colaborador colaborador, Projeto projeto, Date dtRateioInicial, Date dtRateioFinal, List<DetalheRateio> detalheRateios) {
this.cdRateio = cdRateio;
this.colaborador = colaborador;
this.projeto = projeto;
this.dtRateioInicial = dtRateioInicial;
this.dtRateioFinal = dtRateioFinal;
this.detalheRateios = detalheRateios;
}
@Id
@SequenceGenerator(name = "sg_RATEIO_SEQ", sequenceName = "RATEIO_SEQ", allocationSize = 1)
@GeneratedValue(generator = "sg_RATEIO_SEQ")
@Column(name = "CD_RATEIO", nullable = false, scale = 0)
public Long getCdRateio() {
return this.cdRateio;
}
public void setCdRateio(Long cdRateio) {
this.cdRateio = cdRateio;
}
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "CD_COLABORADOR", nullable = true)
public Colaborador getColaborador() {
return this.colaborador;
}
public void setColaborador(Colaborador colaborador) {
this.colaborador = colaborador;
}
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "CD_PROJETO", nullable = true)
public Projeto getProjeto() {
return this.projeto;
}
public void setProjeto(Projeto projeto) {
this.projeto = projeto;
}
@Column(name = "DT_RATEIO_INICIAL", nullable = false)
public Date getDtRateioInicial() {
return this.dtRateioInicial;
}
public void setDtRateioInicial(Date dtRateioInicial) {
this.dtRateioInicial = dtRateioInicial;
}
@Column(name = "DT_RATEIO_FINAL", nullable = true)
public Date getDtRateioFinal() {
return this.dtRateioFinal;
}
public void setDtRateioFinal(Date dtRateioFinal) {
this.dtRateioFinal = dtRateioFinal;
}
@OneToMany(targetEntity=DetalheRateio.class, mappedBy = "rateio")
public List<DetalheRateio> getDetalheRateios() {
return this.detalheRateios;
}
public void setDetalheRateios(List<DetalheRateio> detalheRateios) {
this.detalheRateios = detalheRateios;
}
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "CD_TAREFA", nullable = true)
public Tarefa getTarefa() {
return tarefa;
}
public void setTarefa(Tarefa tarefa) {
this.tarefa = tarefa;
}
@Enumerated(EnumType.ORDINAL)
public TipoRateio getTipo() {
return tipo;
}
public void setTipo(TipoRateio tipo) {
this.tipo = tipo;
}
@Transient
public boolean isFlagAtividade() {
return flagAtividade;
}
public void setFlagAtividade(boolean flagAtividade) {
this.flagAtividade = flagAtividade;
}
}
И моя вторая сущность:
@Entity
@Table(name = "DETALHE_RATEIO")
@Audited
public class DetalheRateio implements Serializable {
private static final long serialVersionUID = 4109721744851677683L;
private Long cdDetalheRateio;
private Rateio rateio;
private AtividadeOs atividadeOs;
private float vlPorcentagem;
public DetalheRateio() {
}
public DetalheRateio(Long cdDetalheRateio, Rateio rateio, AtividadeOs atividadeOs, float vlPorcentagem) {
this.cdDetalheRateio = cdDetalheRateio;
this.rateio = rateio;
this.atividadeOs = atividadeOs;
this.vlPorcentagem = vlPorcentagem;
}
@Id
@SequenceGenerator(name = "sg_DET_RATEIO_SEQ", sequenceName = "DET_RATEIO_SEQ", allocationSize = 1)
@GeneratedValue(generator = "sg_DET_RATEIO_SEQ")
@Column(name = "CD_DETALHE_RATEIO", nullable = false, scale = 0)
public Long getCdDetalheRateio() {
return this.cdDetalheRateio;
}
public void setCdDetalheRateio(Long cdDetalheRateio) {
this.cdDetalheRateio = cdDetalheRateio;
}
@ManyToOne(targetEntity = Rateio.class, cascade=CascadeType.ALL)
@JoinColumn(name = "CD_RATEIO", nullable = false)
public Rateio getRateio() {
return this.rateio;
}
public void setRateio(Rateio rateio) {
this.rateio = rateio;
}
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "CD_ATIVIDADE_OS", nullable = false)
public AtividadeOs getAtividadeOs() {
return this.atividadeOs;
}
public void setAtividadeOs(AtividadeOs atividadeOs) {
this.atividadeOs = atividadeOs;
}
@Column(name = "VL_PORCENTAGEM", nullable = false, precision = 19, scale = 2, columnDefinition = "NUMBER")
public float getVlPorcentagem() {
return this.vlPorcentagem;
}
public void setVlPorcentagem(float vlPorcentagem) {
this.vlPorcentagem = vlPorcentagem;
}
}
Хорошо, пока все хорошо. Теперь у меня есть класс, который расширяет EntityHome из JBoss Seam, и именно этот класс пытается обновить мою сущность. Вот код:
@Name("rateioHome")
public class RateioHome extends EntityHome<Rateio> {
@SuppressWarnings("unchecked")
@Override
@Transactional
public String update() {
String result = null;
boolean valid = true;
if (getPercentualTotal().doubleValue() < 100 || instance.getDetalheRateios().size() < 2) {
facesMessages.addFromResourceBundle(Severity.ERROR, "rateio.erro.atividade");
valid = false;
}
if (instance.getDtRateioFinal() != null && instance.getDtRateioFinal().before(instance.getDtRateioInicial())) {
facesMessages.addFromResourceBundle(Severity.ERROR, "rateio.erro.data");
valid = false;
}
if (valid) {
Rateio rateio = super.find();
List<DetalheRateio> detalheRateios = getInstance().getDetalheRateios();
List<DetalheRateio> detalheRateiosBd = rateio.getDetalheRateios();
Map<Long, DetalheRateio> mapDetalheRateio = new HashMap<Long, DetalheRateio>();
if (detalheRateiosBd != null && detalheRateiosBd.size() > 0) {
Rateio _rateio = getInstance();
for (DetalheRateio item : detalheRateiosBd) {
if (item.getCdDetalheRateio() != null) {
item.getRateio().setDtRateioInicial(_rateio.getDtRateioInicial());
item.getRateio().setDtRateioFinal(_rateio.getDtRateioFinal());
mapDetalheRateio.put(item.getCdDetalheRateio(), item);
}
}
}
List<DetalheRateio> novos = (List<DetalheRateio>) CollectionUtils.subtract(detalheRateios, detalheRateiosBd);
List<DetalheRateio> excluidos = (List<DetalheRateio>) CollectionUtils.subtract(detalheRateiosBd, detalheRateios);
detalheRateiosBd.removeAll(excluidos);
detalheRateiosBd.addAll(novos);
setInstance(rateio);
result = super.update();
getEntityManager().flush();
}
return result;
}
}
Теперь проблема. Когда я попытался обновить сущность на линии: result = super.update();
Я сталкиваюсь с этим исключением:
javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: br.com.entity.DetalheRateio
Я пытался найти метод merge
на EntityHome, но я ничего не нашел. Это устаревший код, который я должен поддерживать, и я не эксперт в JBoss Seam. Если вам нужна дополнительная информация, пожалуйста, дайте мне знать.
1 ответ
Просто нашел решение. Список объектов DetalheRateio
должны быть объединены (сохранены) перед обновлением объекта Rateio
, Я думал, что объект DetalheRateio как Rateio
ребенок будет сохранен "автоматически JPA. Моя ошибка. Итак, я слил вручную каждый DetalheRateio
объект. Фрагмент, который я использовал для этого:
List<DetalheRateio> novos = (List<DetalheRateio>) CollectionUtils.subtract(detalheRateios, detalheRateiosBd);
List<DetalheRateio> excluidos = (List<DetalheRateio>) CollectionUtils.subtract(detalheRateiosBd, detalheRateios);
List<DetalheRateio> detalhesAlterados = new ArrayList<DetalheRateio>();
detalheRateiosBd.removeAll(excluidos);
detalheRateiosBd.addAll(novos);
for (DetalheRateio detalheExcluido : excluidos) {
getEntityManager().remove(detalheExcluido);
}
for (DetalheRateio dRateio : detalheRateios) {
detalhesAlterados.add(getEntityManager().merge(dRateio));
}
rateio.setDetalheRateios(detalhesAlterados);
setInstance(rateio);
result = super.update();
getEntityManager().flush();