我有以下课程/关系(getters& setters未显示但存在):
public class Contract implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Long id;
@Version
@Column(name = "version")
private Integer version;
private String number;
private String volume;
@OneToMany(cascade=CascadeType.REMOVE)
@JoinTable(joinColumns = @JoinColumn(name = "contract_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "attachment_id", referencedColumnName = "id"))
private List<Attachment> attachments;
}
public class Attachment implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Long id;
@Version
@Column(name = "version")
private Integer version;
@Lob
@Basic(fetch=FetchType.LAZY)
@Column(length=2147483647)
private byte[] contents;
private String name;
}
根据我的需要/设计,我使用的是连接表。
如果我想从合同中删除附件,我需要加载合同,然后遍历所有附件,直到找到要删除的附件并将其从列表中删除。
虽然这是有用的,但它需要大量的数据库通信。如果附件列表很长,并且包含大量内容,则还需要大带宽。
还有其他方法可以将其删除吗?如果我尝试直接删除附件(例如:Attachment.findById()。delete()),它将因FK关系而失败 - 赢了吗? (我还没试过这个,但我怀疑它)。
此外,如果我有一个非常大的附件列表,逐个迭代它们直到找到正确的附件也不是很有效。
JPA是否提供任何其他/更好的解决方案?
答案 0 :(得分:1)
我知道有一种解决方法 - 您可以为连接表创建实体类。
您必须在@JoinTable
注释(名称属性)中为您的联接表命名,让我们说ContractAttachment
。然后你可以创建实体:
@Entity(name = "ContractAttachment") // note the same name of table
@IdClass(ContractAttachmentId.class)
public class ContractAttachment implements Serializable {
static final long serialVersionUID = 1L;
@Id
@ManyToOne
@JoinColumn(name="contract_id") // same mappings for columns
private Contract contract;
@Id
@ManyToOne(cascade = CascadeType.REMOVE)
@JoinColumn(name="attachment_id") // same mappings for columns
private Attachment attachment;
// you will also have to override equals and hashcode methods here
}
班级ContractAttachmentId
应如下所示:
public class ContractAttachmentId implements Serializable {
private long contract; // note the same fields names
private long attachment;
// this class should also implement hashcode and equals
}
现在您可以删除连接表中的单个条目,甚至也可以删除附件对象。
ContractAttachment ca = em.createQuery("select ca from ContractAttachment ca " +
"where ca.contract = :contract and ca.attachment = :attachment")
.setParameter("contract", selectedContract)
.setParameter("attachement", selectedAttachment)
.getSingleResult();
em.remove(ca);