有没有办法删除@OneToMany关系中的子实体(使用JoinTable)而无需获取完整的集合?

时间:2014-07-03 19:16:21

标签: java hibernate jpa entity spring-data

我有以下课程/关系(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是否提供任何其他/更好的解决方案?

1 个答案:

答案 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);