2015-10-15 76 views
2

錯誤NHibernate的沒有會話或會話關閉

初始化[Core.Model.Account#2586] -failed懶洋洋地初始化角色的集合:Core.Model.Account.Roles,沒有會話或會話被關閉

當我嘗試使用NHibernate在我的web應用程序中登錄時出現。我不明白的是如何關閉連接,因爲當我調試到調用方法時,我可以打開使用的NHibernate會話的isOpen屬性。

但是,只要延遲加載啓動,顯然NHibernate認爲連接已關閉。這怎麼會發生?

我按照建議在BeginRequest中啓動我的NHibernate會話,並在EndRequest中關閉它們。

Account.cs(項目/命名空間/組裝Core

public class Account 
{ 
    // ... 

    public virtual ISet<Role> Roles 
    { 
     get; 
     set; 
    } 

    // ... 

    public virtual bool HasPermission(Permission permission_) 
    { 
     foreach (Role role in Roles) { 
      if (role.Permissions.Contains(Permission.ALL) || role.Permissions.Contains(permission_)) { 
       return true; 
      } 
     } 
     return false; 
    } 
} 

Account.hbm.xml(項目/命名空間/組裝Core

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"> 
    <class name="Core.Model.Account,Core" table="accounts"> 
     <!-- ... --> 
     <set name="Roles" table="account_roles" lazy="true"> 
      <key column="account"/> 
      <many-to-many class="Core.Model.Role" column="role" /> 
     </set> 
    </class> 
</hibernate-mapping> 

全球.asax(在項目/命名空間/程序集Web

public AccountRepository Accounts; 
private static ISessionFactory _sessionFactory; 
private void Application_Start(object sender_, EventArgs e_) 
{ 
    _sessionFactory = new Configuration().Configure().BuildSessionFactory(); 
} 


private void Application_BeginRequest(object sender_, EventArgs e_) 
{ 
    ISession session = _sessionFactory.OpenSession(); 
    Accounts.SetSession(session); 
    HttpContext.Current.Items.Add("HibernateSession", session); 
} 

private void Application_EndRequest(object sender_, EventArgs e_) 
{ 
    ISession session = HttpContext.Current.Items["HibernateSession"] as ISession; 
    if (session != null && session.IsOpen) { 
     session.Close(); 
     HttpContext.Current.Items.Remove("HibernateSession"); 
    } 
} 

DecoratedSession.cs(在項目/命名空間/組件Web

private static HttpSessionState _session 
{ 
    get 
    { 
     return HttpContext.Current.Session; 
    } 
} 

public static T Get<T>(string key_) 
{ 
    if (_session == null || _session[key_] == null) { 
     return default(T); 
    } 
    return (T)_session[key_]; 
} 

public static void Set<T>(string key_, T value_) 
{ 
    _session[key_] = value_; 
} 

public static Account Account 
{ 
    get 
    { 
     return Get<Account>("Account"); 
    } 
    set 
    { 
     Set<Account>("Account", value); 
    } 
} 

login.aspx的(在項目/命名空間/組件Web

protected void loginButton_Click(object sender, System.EventArgs e) 
{ 
    DecoratedSession.Account = Global.Firewall.Login(tb_user.Text, tb_user.Text); 
    Response.Redirect("main.aspx", true); 
} 

主.aspx(在項目/命名空間/程序集Web

protected void Page_Load(object sender, System.EventArgs e) 
{ 
    // Error thrown here, when accessing the "roles" set 
    if (DecoratedSession.Account.HasPermission(Permission.FULL_ACCESS)) 
    { 
     // ... 
    } 
} 

我甚至可以在會話雙頭呆日誌文件看,然後出現異常,然後將其關閉。

Global: 15:20:08,669 DEBUG Global - Opened session [529000] for request to [/main.aspx] 
Global: 15:20:08,670 DEBUG Global - STARTREQUEST Session id: [529000] 
main: 15:20:08,682 DEBUG main - MAIN Session id: [529000] 
NHibernate.LazyInitializationException: 15:20:08,685 ERROR NHibernate.LazyInitializationException - Initializing[Core.Model.Account#2586]-failed to lazily initialize a collection of role: Core.Model.Account.Roles, no session or session was closed 
NHibernate.LazyInitializationException: Initializing[Core.Model.Account#2586]-failed to lazily initialize a collection of role: Core.Model.Account.Roles, no session or session was closed 
Global: 15:20:14,160 DEBUG Global - Closed session [529000] for request to [/main.aspx] 

我該如何調試?

回答

2

的位置點是(我沒有深入到上面的代碼,但基於沒有我的經驗)相關靜態 VS HTTP請求生命週期。

雖然有打開的會話,被關閉指責爲本屆會議的對象來自以前的一些(與另一個網絡請求)

檢查一些細節在這裏:

解決方案我在介紹某種原型模式時看到:

[Serializable] 
public class Account, ICloneable, ... 
{ 
    ... 
    public override object Clone() 
    { 
     var entity = base.Clone() as Account; 
     entity.Roles = ... (clone roles) 
     ... 
     return entity; 
    } 
    ... 

而對於認證加載帳戶(用戶,角色)的時候,我們應該叫Clone(),以確保所有重要特性(多到一,一到多)加載,並隨後準備使用。該克隆可以緩存在靜態環境中

+0

但是,這很難成爲如何處理NHibernate的「登錄」會話的正確方式,對吧?我在另一個網絡應用中做了完全相同的事情,它在那裏工作得很好...... –

+1

老實說,我的所有安全性總是被加載一次,克隆和緩存。它後來與當前用戶進行比較... –

+0

好的,感謝您的輸入。我想我弄明白了爲什麼它可以在我的其他應用程序中工作:在一個有效的工作中,在我從數據庫中獲得'Account'後,立即訪問'Roles/Permissions'字段,因此強制它加載到會話中。我不會在另一個應用程序上這樣做,因此錯誤...您能解釋您如何「克隆和緩存」安全細節?我想我也需要這樣做。 –

相關問題