jpa vue管理系统
这是我关于JPA 2.1实体图的第二篇文章。 第一篇文章描述了命名实体图的用法。 这些可用于定义在编译时将使用查找或查询方法获取的实体和/或属性的图形。 动态实体图以相同的方式但以动态方式这样做。 这意味着您可以在运行时使用EntityGraph API定义实体图。
如果您错过了第一篇文章,并且想阅读如何定义命名实体图或JPA 2.0如何解决延迟加载问题,请查看以下文章: JPA 2.1实体图–第1部分:命名实体图。
示例实体
我们将使用与上一篇文章相同的示例。 因此,如果您已阅读另一段,则可以跳过此段。
我们将使用3个实体。 它们是Order , OrderItem和Product 。 一个Order可能包含多个OrderItems ,每个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;
@Column
private 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;
@Column
private int quantity;
@ManyToOne
private 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;
@Column
private 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);
里面发生什么事了?
与上一篇文章一样,我们希望查看Hibernate日志,并找出Hibernate状态。 如我们所见,动态实体图的结果与命名实体图的结果相同。 它会创建一个加载计划和一个包含所有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相比,这是一个非常有用的扩展。 尤其是动态实体图对于基于运行时信息(例如方法参数)定义获取策略很有用。
jpa vue管理系统