这是我关于JPA 2.1实体图的第二篇文章。 第一篇文章描述了命名实体图的用法。 这些可用于定义在编译时将使用查找或查询方法获取的实体和/或属性的图形。 动态实体图以相同的方式但以动态方式这样做。 这意味着您可以在运行时使用EntityGraph API定义实体图。
如果您错过了第一篇文章,并且想阅读如何定义命名实体图或JPA 2.0如何解决延迟加载问题,请查看以下文章: JPA 2.1实体图–第1部分:命名实体图 。
示例实体
我们将使用与上一篇文章相同的示例。 因此,如果您已阅读另一段,则可以跳过此段。
我们将使用3个实体。 它们是Order , OrderItem和Product 。 一个Order可能包含多个OrderItem ,每个OrderItem都属于一个Product 。 所有这些关系的FetchType都是FetchType.LAZY。 因此,默认情况下,实体管理器不会从数据库中获取它们,而是使用代理对其进行初始化。
订单实体:
@Entity
@Table(name = "purchaseOrder")
@NamedEntityGraph(name = "graph.Order.items", attributeNodes = @NamedAttributeNode(value = "items", subgraph = "items"), subgraphs = @NamedSubgraph(name = "items", attributeNodes = @NamedAttributeNode("product")))
public class Order implements Serializable {@Id@GeneratedValue(strategy = GenerationType.AUTO)@Column(name = "id", updatable = false, nullable = false)private Long id = null;@Version@Column(name = "version")private int version = 0;@Columnprivate String orderNumber;@OneToMany(mappedBy = "order", fetch = FetchType.LAZY)private Set<OrderItem> items = new HashSet<OrderItem>();...
OrderItem实体:
@Entity
public class OrderItem implements Serializable
{@Id@GeneratedValue(strategy = GenerationType.AUTO)@Column(name = "id", updatable = false, nullable = false)private Long id = null;@Version@Column(name = "version")private int version = 0;@Columnprivate int quantity;@ManyToOneprivate Order order;@ManyToOne(fetch = FetchType.LAZY)private Product product;
产品实体:
@Entity
public class Product implements Serializable
{@Id@GeneratedValue(strategy = GenerationType.AUTO)@Column(name = "id", updatable = false, nullable = false)private Long id = null;@Version@Column(name = "version")private int version = 0;@Columnprivate String name;
动态实体图
因此,让我们定义一个动态实体图。 我们将与第一篇文章中的操作相同,并定义一个简单的实体图,该图告诉实体管理器获取带有所有相关OrderItem的Order 。 因此,我们使用实体管理器的createEntityGraph(Class rootType)方法为Order实体创建实体图。 在下一步中,我们创建将与该实体图一起获取的Order实体的所有属性的列表。 我们只需要添加属性items ,因为我们将使用该实体图作为加载图,并且默认情况下所有其他属性都渴望使用。
如果我们将此实体图用作提取图,则需要将所有属性添加到应从数据库中提取的列表中。
EntityGraph<Order> graph = this.em.createEntityGraph(Order.class);
graph.addAttributeNodes("items");Map<String, Object> hints = new HashMap<String, Object>();
hints.put("javax.persistence.loadgraph", graph);this.em.find(Order.class, orderId, hints);
好的,动态定义应从数据库中获取实体的哪些属性很不错。 但是,如果我们需要实体图呢? 像使用其所有OrderItems及其产品获取订单 ?
这可以通过子图来完成。 子图基本上是一个嵌入到另一个实体图或实体子图中的实体图。 子图的定义类似于实体图的定义。 为了创建并嵌入子图到实体图,我们需要调用addSubgraph(字符串的attributeName)方法EntityGraph对象上。 这将为具有给定名称的属性创建一个子图。 在下一步中,我们需要定义此子图应获取的属性列表。
以下代码段显示了带有实体子图的实体图的定义,该图指示实体管理器获取带有OrderItem及其Product的Order 。
EntityGraph<Order> graph = this.em.createEntityGraph(Order.class);
Subgraph<OrderItem> itemGraph = graph.addSubgraph("items");
itemGraph.addAttributeNodes("product");Map<String, Object> hints = new HashMap<String, Object>();
hints.put("javax.persistence.loadgraph", graph);return this.em.find(Order.class, orderId, hints);
里面发生什么事了?
与上一篇文章一样,我们希望查看休眠日志,并找出休眠状态。 如我们所见,动态实体图的结果与命名实体图的结果相同。 它创建一个负载计划和一个包含所有3个实体的一条select语句。
2014-04-07 20:08:15,260 DEBUG [org.hibernate.loader.plan.build.spi.LoadPlanTreePrinter] (default task-2) LoadPlan(entity=blog.thoughts.on.java.jpa21.entity.graph.model.Order)- Returns- EntityReturnImpl(entity=blog.thoughts.on.java.jpa21.entity.graph.model.Order, querySpaceUid=, path=blog.thoughts.on.java.jpa21.entity.graph.model.Order)- CollectionAttributeFetchImpl(collection=blog.thoughts.on.java.jpa21.entity.graph.model.Order.items, querySpaceUid=, path=blog.thoughts.on.java.jpa21.entity.graph.model.Order.items)- (collection element) CollectionFetchableElementEntityGraph(entity=blog.thoughts.on.java.jpa21.entity.graph.model.OrderItem, querySpaceUid=, path=blog.thoughts.on.java.jpa21.entity.graph.model.Order.items.)- QuerySpaces- EntityQuerySpaceImpl(uid=, entity=blog.thoughts.on.java.jpa21.entity.graph.model.Order)- SQL table alias mapping - order0_- alias suffix - 0_- suffixed key columns - {id1_2_0_}- JOIN (JoinDefinedByMetadata(items)) : -> - CollectionQuerySpaceImpl(uid=, collection=blog.thoughts.on.java.jpa21.entity.graph.model.Order.items)- SQL table alias mapping - items1_- alias suffix - 1_- suffixed key columns - {order_id4_2_1_}- entity-element alias suffix - 2_- 2_entity-element suffixed key columns - id1_0_2_- JOIN (JoinDefinedByMetadata(elements)) : -> - EntityQuerySpaceImpl(uid=, entity=blog.thoughts.on.java.jpa21.entity.graph.model.OrderItem)- SQL table alias mapping - items1_- alias suffix - 2_- suffixed key columns - {id1_0_2_}2014-04-07 20:08:15,260 DEBUG [org.hibernate.loader.entity.plan.EntityLoader] (default task-2) Static select for entity blog.thoughts.on.java.jpa21.entity.graph.model.Order [NONE:-1]: select order0_.id as id1_2_0_, order0_.orderNumber as orderNum2_2_0_, order0_.version as version3_2_0_, items1_.order_id as order_id4_2_1_, items1_.id as id1_0_1_, items1_.id as id1_0_2_, items1_.order_id as order_id4_0_2_, items1_.product_id as product_5_0_2_, items1_.quantity as quantity2_0_2_, items1_.version as version3_0_2_ from purchaseOrder order0_ left outer join OrderItem items1_ on order0_.id=items1_.order_id where order0_.id=?
结论
在第一篇文章中定义了命名实体图之后 ,我们现在使用EntityGraph API定义动态实体图。 使用此实体图,我们可以仅从数据库中查询一次就获取多个实体的图。 这可用于解决LazyInitializationException并提高应用程序的性能。
您如何看待(动态)实体图? 从我的角度来看,与JPA 2.0相比,这是一个非常有用的扩展。 特别是动态实体图对于基于运行时信息(例如方法参数)定义获取策略很有用。
翻译自: https://www.javacodegeeks.com/2014/05/jpa-2-1-entity-graph-part-2-define-lazyeager-loading-at-runtime.html