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

NHibernate 實戰避坑指南:四大常見異常原因與解決方案

     編輯:關於.NET

前言

NHibernate 作為 .NET 領域最成熟的 ORM 框架,功能強大但學習曲線陡峭。本文整理實務開發中最高頻的四大異常——LazyInitializationException、無主鍵表映射、複合主鍵實作、外鍵重複參數——並提供標準解決模式與最佳實踐。

問題一:Could not initialize proxy - no Session

異常堆疊:NHibernate.LazyInitializationException: could not initialize proxy - no Session

根因:many-to-one 預設 lazy="proxy",當嘗試存取導航屬性時,若 Session 已關閉,無法發出 SQL 載入關聯物件。

解決方案:

<!-- 方案 A:關閉延遲載入(適用於經常需要的關聯) -->
<many-to-one name="Order" column="ORDER_ID" class="Order" lazy="false" />

<!-- 方案 B:在 set 集合上關閉延遲(會產生額外查詢,慎用) -->
<set name="OrderDetails" lazy="false"> ... </set>

最佳實踐:僅在 many-to-one 設定 lazy="false";集合保持預設 lazy="true",在 Service Layer 以 FetchMode.Eager 或 FetchMode.Join 明確指定抓取策略,避免 N+1 問題。

問題二:無主鍵表如何編寫 .hbm.xml

場景**:明細表(如 OrderDetail)常以複合鍵 (OrderId, ProductId) 唯一識別,資料庫未建立單一 PK 欄位。

錯誤做法**:省略 <id> 節點 → NHibernate 拋出映射驗證錯誤。

正確做法:使用 <composite-id> 定義複合主鍵**

<composite-id>
    <key-property name="OrderId" column="ORDER_ID" />
    <key-property name="ProductId" column="PRODUCT_ID" />
</composite-id>

也可將所有欄位納入複合鍵(極端情況):

<composite-id>
    <key-property name="Amount" />
    <key-property name="CreateTime" />
    <key-property name="ModifyTime" />
</composite-id>

問題三:複合主鍵實體必須實作 Equals 與 GetHashCode

規則**:NHibernate 使用複合主鍵物件作為快取鍵與集合元素比較依據,若未正確實作 Equals / GetHashCode,會導致快取失效、重複實體、集合操作異常。

標準實作模板**

public class OrderDetail
{
    public virtual int OrderId { get; set; }
    public virtual int ProductId { get; set; }
    public virtual decimal Amount { get; set; }

    public override bool Equals(object obj)
    {
        var other = obj as OrderDetail;
        if (other == null) return false;
        return OrderId == other.OrderId && ProductId == other.ProductId;
    }

    public override int GetHashCode()
    {
        unchecked
        {
            int hash = 17;
            hash = hash * 23 + OrderId.GetHashCode();
            hash = hash * 23 + ProductId.GetHashCode();
            return hash;
        }
    }
}

注意**:GetHashCode 必須基於不可變的主鍵屬性計算,避免物件加入 HashSet/Dictionary 後雜湊值改變導致找不到元素。

問題四:SqlServerParameterCollection Count=4 索引 4 無效

異常訊息**:Index 4 is invalid for SqlParameterCollection with Count=4

根因**:從表映射主表時,many-to-one 的外鍵欄位同時出現在 insert 與 update 敘述,導致參數重複。

錯誤映射**

<many-to-one name="Dictate" column="DICTATE_ID" class="Dictate" />

修正映射:標記 insert/update=false**

<many-to-one name="Dictate" column="DICTATE_ID" class="Dictate"
             insert="false" update="false" />

原理**:外鍵值由主表端(如 Dictate.OrderDetails 的 key 欄位)維護,從表端僅負責讀取,不參與寫入,避免參數重複。

總結:NHibernate 映射黃金法則

  1. 預設開啟延遲載入,在 Repository/Service 層以 FetchStrategy 精確控制。
  2. 無單一主鍵表必須使用 <composite-id>。
  3. 複合主鍵實體強制實作 Equals / GetHashCode。
  4. 雙向關聯的「被動端」many-to-one 加上 insert="false" update="false"。
  5. 善用 NHibernate.Profiler 或 SQL Profiler 監控實際 SQL,驗證映射正確性。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved