首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

NHibernate實戰(10):一對多關聯查詢三大方式詳解

     編輯:關於.NET

前言

基於 Customer-Order 父子關係,本文系統講解 NHibernate 三大查詢方式(原生 SQL、HQL、Criteria API)在關聯查詢中的具體應用,並深入探討 Criteria API 的結果轉換與投影技巧。

關聯查詢場景

查詢擁有指定日期後訂單的客戶列表,Customer 1∶N Order。

三種查詢方式對比

1. 原生 SQL 查詢

public IList<Customer> UseSQL_GetCustomersWithOrders(DateTime orderDate)
{
    return _session.CreateSQLQuery(
        "select distinct {customer.*} from Customer {customer}" +
        " inner join [Order] o on o.Customer={customer}.CustomerId" +
        " where o.OrderDate > :orderDate")
    .AddEntity("customer", typeof(Customer))
    .SetDateTime("orderDate", orderDate)
    .List<Customer>();
}

關鍵語法:{customer.*} 代表 Customer 所有屬性,AddEntity 映射結果集到實體。

2. HQL 查詢

public IList<Customer> UseHQL_GetCustomersWithOrders(DateTime orderDate)
{
    return _session.CreateQuery(
        "select distinct c from Customer c, " +
        "c.Orders.elements o where o.OrderDate > :orderDate")
    .SetDateTime("orderDate", orderDate)
    .List<Customer>();
}

測試驗證:斷言查詢結果客戶數為 1,且其訂單日期滿足條件。

3. Criteria API 查詢

基礎版(含重複結果)

public IList<Customer> UseCriteriaAPI_GetCustomersWithOrders(DateTime orderDate)
{
    return _session.CreateCriteria(typeof(Customer))
        .CreateCriteria("Orders")
        .Add(Restrictions.Gt("OrderDate", orderDate))
        .List<Customer>();
}

問題:一對多關聯導致父實體重複,生成 SQL 無 DISTINCT。

進階:結果轉換器去重

public IList<Customer> UseCriteriaAPI_GetCustomersWithOrders(DateTime orderDate)
{
    return _session.CreateCriteria(typeof(Customer))
        .CreateCriteria("Orders")
        .Add(Restrictions.Gt("OrderDate", orderDate))
        .SetResultTransformer(new NHibernate.Transform.DistinctRootEntityResultTransformer())
        // 或 .SetResultTransformer(NHibernate.CriteriaUtil.DistinctRootEntity)
        .List<Customer>();
}

原理:記憶體層面去重,不修改 SQL,適用於分頁查詢前預處理。

進階:投影查詢去重

public IList<Customer> UseCriteriaAPI_GetDistinctCustomers(DateTime orderDate)
{
    // 步驟1:查詢去重後的 CustomerId 集合
    IList<int> ids = _session.CreateCriteria(typeof(Customer))
        .SetProjection(Projections.Distinct(Projections.ProjectionList()
            .Add(Projections.Property("CustomerId"))))
        .CreateCriteria("Orders")
        .Add(Restrictions.Gt("OrderDate", orderDate))
        .List<int>();

    // 步驟2:根據 ID 列表查詢完整實體
    return _session.CreateCriteria(typeof(Customer))
        .Add(Restrictions.In("CustomerId", ids.ToArray<int>()))
        .List<Customer>();
}

優勢:SQL 層面 DISTINCT,減少傳輸數據量,適合大數據集場景。Projections 工廠提供豐富聚合函數。

Criteria API 核心技巧總結

技術適用場景SQL 影響性能特點
CreateCriteria 導航動態多層關聯約束生成 JOIN直觀易維護
DistinctRootEntityResultTransformer記憶體去重、分頁前處理無 DISTINCT需載入重複行
Projection + Distinct + In 查詢大數據集、需 SQL 層面去重含 DISTINCT兩次查詢、傳輸少

結語

一對多關聯查詢中,HQL 最貼近對象思維,Criteria API 最靈活強大。掌握結果轉換器與投影組合,能優雅解決重複結果難題。下篇將建立一對多映射基礎配置。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved