jpa 循环引用
在上一篇文章中 ,我提到我选择通过其主键而不是类型来引用其他聚合。 在处理大型或复杂域模型时,我通常使用这种方法(也称为断开域模型)。 在本文中,让我尝试进一步解释如何在JPA中完成它。 请注意,生成DDL脚本不会创建一个外键约束(不像所示的一个以前的帖子 )。
通过身份引用
在大多数JPA示例中,每个实体都引用另一个实体,或者被另一个实体引用。 这导致了一个对象模型,该对象模型允许从一个实体到任何其他实体的遍历。 这可能导致不必要的遍历 (以及持久性操作的不必要的级联)。 这样,最好通过按ID(而不是按类型)引用其他实体来防止这种情况。
下面的代码显示OrderItem
如何通过其主键(而不是类型)引用Product
实体。
@Entity
public class Product {@Id private Long id;// ...
}@Entity
public class Order {// ...@OneToMany(mappedBy="order")private Collection<OrderItem> items;
}@Entity
public class OrderItem {// ...@ManyToOneprivate Order order;// @ManyToOne// private Product product;private Long productId;// ...
}
有几种获取关联的Product
实体的方法。 一种方法是使用存储库查找具有ID的产品(具有findByIdIn(List<Long> ids)
方法的ProductRepository
)。 如之前的评论中所述,请注意不要以N + 1选择问题告终。
也可以使用自定义身份类型。 下面的示例使用ProductId
。 它是一个价值对象。 而且由于JPA,我们需要添加零参数构造函数。
@Embeddable
public class ProductId {private Long id;public ProductId(long id) {this.id = id;}public long getValue() { return id; }// equals and hashCodeprotected ProductId() { /* as required by JPA */ }
}@Entity
public class Product {@EmbeddedId private ProductId id;// ...
}@Entity
public class Order { // ...@OneToMany(mappedBy="order")private Collection<OrderItem> items;
}@Entity
public class OrderItem {// ...@ManyToOneprivate Order order;// @ManyToOne// private Product product;@Embedded private ProductId productId;// ...
}
但是,如果您将生成的值用于ID,则此方法将无效。 幸运的是,从JPA 2.0开始,围绕此有一些技巧,我将在下一部分中分享这些技巧。
生成的ID
在JPA中,当使用非@Basic
类型作为@Id
,我们不能再使用@GeneratedValue
。 但是,通过混合使用属性和字段访问,我们仍然可以使用生成的值和ProductId
。
@Embeddable
@Access(AccessType.FIELD)
public class ProductId {...}@Entity
@Access(AccessType.FIELD)
public class Product {@Transient private ProductId id;public ProductId getId() { return id; }// ...private Long id_;@Id@GeneratedValue(strategy=...)@Access(AccessType.PROPERTY)protected Long getId_() { return id_; }protected void setId_(Long id_) {this.id_ = id_;this.id = new ProductId(this.id_);}
}@Entity
public class Order { // ...@OneToMany(mappedBy="order")private Collection<OrderItem> items;
}@Entity
public class OrderItem {// ...@ManyToOneprivate Order order;// @ManyToOne// private Product product;@Embedded private ProductId productId;// ...
}
诀窍包括将属性访问权限用于生成的ID值(同时保留其余访问权限)。 这导致JPA使用setter方法。 然后在其中初始化ProductId
字段。 请注意, ProductId
字段不会@Transient
(标记为@Transient
)。
希望这可以帮助。
翻译自: https://www.javacodegeeks.com/2016/07/reference-identity-jpa.html
jpa 循环引用