具有以下簡化實體:如何避免1 + n數據庫調用Hibernate中的雙向可選一對一關聯?
@MappedSuperclass
public abstract class AbstractEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
protected Long id;
}
@Entity
@Table(name = "t_invoice")
public class Invoice extends AbstractEntity {
@OneToOne(optional = false, fetch = FetchType.EAGER)
@JoinColumn(name = "order_id")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private Order order;
}
@Entity
@Table(name = "t_order")
public class Order extends AbstractEntity {
@OneToMany(mappedBy = "order", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@SortNatural
private SortedSet<OrderLine> orderLines = new TreeSet<>();
@OneToOne(optional = true, mappedBy = "order", fetch = FetchType.EAGER)
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private Invoice invoice;
}
和以下使用庫彈簧數據
public interface InvoiceRepository extends JpaRepository<Invoice, Long> {
List<Invoice> findDistinctByInvoiceDateBetween(LocalDate from, LocalDate until);
}
使用庫方法擷取發票時1 + N SQL語句作爲日誌中被示出執行:
SELECT DISTINCT i.id, ... FROM t_invoice i WHERE i.invoice_date BETWEEN ? AND ?;
SELECT i.id, ... FROM t_invoice i WHERE i.order_id = ?;
SELECT i.id, ... FROM t_invoice i WHERE i.order_id = ?;
... n
從this SO我明白,當有一對一的可選聯想離子,Hibernate需要進行n次數據庫調用,以確定訂單中的可選發票是否爲空。 讓我感到困惑的是,Hibernate已經在最初的查詢中提取了有問題的發票,那麼爲什麼它不會使用已獲取的發票中的數據呢?
我也嘗試通過使用@NamedEntityGraph和@NamedSubgraph來按順序填充發票以避免n次調用。
因此現在發票實體的樣子:
@Entity
@NamedEntityGraph(
name = Invoice.INVOICE_GRAPH,
attributeNodes = {
@NamedAttributeNode(value = "order", subgraph = "order.subgraph")
},
subgraphs = {
@NamedSubgraph(name = "order.subgraph", attributeNodes = {
@NamedAttributeNode("invoice"),
@NamedAttributeNode("orderLines")
}),
}
)
@Table(name = "t_invoice")
public class Invoice extends AbstractEntity {
@OneToOne(optional = false, fetch = FetchType.EAGER)
@JoinColumn(name = "order_id")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private Order order;
}
,並在倉庫中的方法是這樣的:
@EntityGraph(value = Invoice.INVOICE_GRAPH, type = EntityGraph.EntityGraphType.LOAD)
List<Invoice> findDistinctByInvoiceDateBetween(LocalDate from, LocalDate until);
但它仍然使n個數據庫調用,即使第一SQL SELECT子句包含發票數據兩次,你可以看到:
SELECT DISTINCT
invoice0_.id AS id1_13_0_,
order1_.id AS id1_14_2_,
orderlines4_.id AS id1_15_4_,
invoice5_.id AS id1_13_5_,
invoice0_.created AS created2_13_0_,
order1_.created AS created2_14_2_,
orderlines4_.created AS created2_15_4_,
invoice5_.created AS created2_13_5_,
FROM t_invoice invoice0_ ... more join clausules ...
WHERE invoice0_.order_id = order1_.id AND (invoice0_.invoice_date BETWEEN ? AND ?)
所以現在我wonderi如何避免n次額外的電話按順序填充發票?