我在使用 EJB 应用程序的 J2EE 中有一个 3 层模型:Cart,它有许多 LineItem,每个 LineItem 都有许多 Book(Book 不一定指 Line Item,它不是 2 向的)。
Cart(1) <--> (M) LineItem (1) --> (M) Book
我希望将其全部加载,即当我提取购物车时,它还应该加载其所有行项目和所有这些书籍,并使用最少数量的 SQL 查询(我正在使用关系数据库,例如 MySQL)。它可以通过 3 个查询来完成,每个查询对应一种类型的对象。设置“FetchType.EAGER”会导致加载所有对象,但它有“2+n”次调用:1 个购物车查询(显然),另一个查询行项目,但随后必须对书籍进行 n 次查询,其中 n 是订单项的数量。
我曾经使用 Ruby on Rails,其中使用急切加载(使用包含)可以满足我的需要。我也可以用 J2EE 来做吗?
(注意:联接可能是一个选项,但我希望从查询中自动填充实体,尽管我认为联接不太舒服)。
我的代码示例:
@Entity
public class Cart implements Serializable {
@OneToMany(cascade=ALL, mappedBy="cart", fetch = FetchType.EAGER)
private List<LineItem> lineItems;
}
@Entity
public class LineItem implements Serializable {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="cart_id", referencedColumnName = "id")
private Cart cart;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name="book_id", referencedColumnName = "id")
private Book book;
}
@Entity
public class Book implements Serializable {
...
}
以下是 SQL 查询示例,其中购物车有 3 个行项目:
SELECT id, name FROM carts WHERE (id = 19)
SELECT id, quantity, book_id, cart_id FROM line_items WHERE (cart_id = 19)
SELECT id, description, name, price FROM books WHERE (id = 4)
SELECT id, description, name, price FROM books WHERE (id = 3)
SELECT id, description, name, price FROM books WHERE (id = 1)
最佳答案
标准 JPA 提供 join fetch ,它标记一个要急切获取的关系,就像通过注释标记为急切一样。在您的情况下,只需要 join fetch
lineItems
,因为 book
将与每个 LineItem
一起加载在单个查询中。
使用 JPA 2.1,您可以使用 Entity graph - 您不需要修改您的查询,只需将一个描述符附加到您的查询中,该描述符定义应立即获取哪些关系。
如果您想优化到尽可能少的查询,您可能需要使用 batch fetching ,这在某些 JPa 提供商中可用。但请注意,没有标准化的方法来打开此功能 - 我只是链接到如何使用 EclipseLink 进行此操作。
关于java - J2EE 实体中的深度预加载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33543899/