Hi, forum followers
I’m trying to implement the deletion of files from FileStorage associated to an instance when this one is deleted.
Entity Anotacio has the attribute ‘fitxers’ as a many to many association with FileDescriptor[sys$FileDescriptor]
package com.company.logistica.entity;
import com.company.mestrelegacy.entity.Article;
import com.company.mestrelegacy.entity.Proces;
import com.company.mestrelegacy.entity.Proveidor;
import com.haulmont.cuba.core.entity.FileDescriptor;
import com.haulmont.cuba.core.entity.StandardEntity;
import com.haulmont.cuba.core.entity.annotation.Lookup;
import com.haulmont.cuba.core.entity.annotation.LookupType;
import com.haulmont.cuba.core.entity.annotation.OnDelete;
import com.haulmont.cuba.core.entity.annotation.PublishEntityChangedEvents;
import com.haulmont.cuba.core.global.DeletePolicy;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import java.util.Date;
import java.util.List;
@Table(name = "LOGIS_ANOTACIO")
@Entity(name = "logis_Anotacio")
@PublishEntityChangedEvents
public class Anotacio extends StandardEntity {
private static final long serialVersionUID = -423410436120639202L;
@Temporal(TemporalType.DATE)
@NotNull
@Column(name = "DATA_", nullable = false)
private Date data;
@OneToMany(mappedBy = "anotacio")
private List<EtiquetaNota> etiquetes;
@Lookup(type = LookupType.SCREEN, actions = {"lookup", "open", "clear"})
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "CONTRACTE_LN_ID")
private ContracteLin contracteLn;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "ARTICLE_ID")
private Article article;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "PROCES_ID")
private Proces proces;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "PROVEIDOR_ID")
private Proveidor proveidor;
@Column(name = "PREU")
private Double preu;
@Column(name = "ASSUMPTE", length = 120)
private String assumpte;
@Lob
@Column(name = "OBSERVACIONS")
private String observacions;
@JoinTable(name = "LOGIS_ANOTACIO_FILE_DESCRIPTOR_LINK",
joinColumns = @JoinColumn(name = "ANOTACIO_ID"),
inverseJoinColumns = @JoinColumn(name = "FILE_DESCRIPTOR_ID"))
@OnDelete(DeletePolicy.CASCADE)
@ManyToMany
private List<FileDescriptor> fitxers;
public List<FileDescriptor> getFitxers() {
return fitxers;
}
public void setFitxers(List<FileDescriptor> fitxers) {
this.fitxers = fitxers;
}
public List<EtiquetaNota> getEtiquetes() {
return etiquetes;
}
public void setEtiquetes(List<EtiquetaNota> etiquetes) {
this.etiquetes = etiquetes;
}
public String getObservacions() {
return observacions;
}
public void setObservacions(String observacions) {
this.observacions = observacions;
}
public String getAssumpte() {
return assumpte;
}
public void setAssumpte(String assumpte) {
this.assumpte = assumpte;
}
public Double getPreu() {
return preu;
}
public void setPreu(Double preu) {
this.preu = preu;
}
public Proveidor getProveidor() {
return proveidor;
}
public void setProveidor(Proveidor proveidor) {
this.proveidor = proveidor;
}
public Proces getProces() {
return proces;
}
public void setProces(Proces proces) {
this.proces = proces;
}
public Article getArticle() {
return article;
}
public void setArticle(Article article) {
this.article = article;
}
public ContracteLin getContracteLn() {
return contracteLn;
}
public void setContracteLn(ContracteLin contracteLn) {
this.contracteLn = contracteLn;
}
public Date getData() {
return data;
}
public void setData(Date data) {
this.data = data;
}
}
The implementation for deleting all files associated to an Anotacio instance when this one is deleted is located on next Event Listener:
package com.company.logistica.listeners;
import com.company.logistica.entity.Anotacio;
import com.haulmont.cuba.core.TransactionalDataManager;
import com.haulmont.cuba.core.app.FileStorageService;
import com.haulmont.cuba.core.app.events.AttributeChanges;
import com.haulmont.cuba.core.app.events.EntityChangedEvent;
import com.haulmont.cuba.core.entity.FileDescriptor;
import com.haulmont.cuba.core.entity.contracts.Id;
import com.haulmont.cuba.core.global.DataManager;
import com.haulmont.cuba.core.global.FileStorageException;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;
import javax.inject.Inject;
import java.util.Collection;
import org.slf4j.Logger;
import java.util.UUID;
@Component("logis_AnotacioChangedListener")
public class AnotacioChangedListener {
@Inject
private DataManager dataManager;
@Inject
private TransactionalDataManager transactionalDataManager;
@Inject
private FileStorageService fileStorageService;
@Inject
private Logger log;
@TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT)
public void beforeCommit(EntityChangedEvent<Anotacio, UUID> event) {
AttributeChanges canvis = event.getChanges();
if (event.getType().equals(EntityChangedEvent.Type.DELETED)){
//Obtenir la llista de fitxers associats al registre Anotacio que s'ha eliminat però encara es troba a BD:
Collection<Id<FileDescriptor, UUID>> fitxers = event.getChanges().getOldCollection("fitxers", FileDescriptor.class);
for (Id<FileDescriptor, UUID> fitxerId : fitxers){
FileDescriptor fitxer = transactionalDataManager.load(fitxerId).one();
try{
//Eliminació del fitxer del FileStorage
fileStorageService.removeFile(fitxer);
} catch (FileStorageException e){
String missatge = "Error a l'eliminar el fitxer";
missatge.concat(" : ".concat(fitxer.getName()));
log.error(missatge, e);
}
}
}
}
}
Application raise Exception:
java.lang.IllegalStateException: No results error when tries to get the FileDescriptor with the following instruction: FileDescriptor fitxer = transactionalDataManager.load(fitxerId).one();
app.log (105.5 KB)
What I’m doing wrong for getting the FileDescriptor of each associated file to the instance?
Thanks in advance.
Xavier Lorente