2008-11-22 9 views

Odpowiedz

1

Jasne, to co kiedyś, kiedy zaczynasz z NHibernate:

Session Fabryka

public class BaseDataAccess 
{ 

protected ISession m_session; 

public BaseDataAccess() 
{ 
m_session=NHibernateHttpModule.CurrentSession; 
} 

public static ISession OpenSession() 
{ 
Configuration config; 
ISessionFactory factory; 
ISession session; 
config = new Configuration(); 

if (config==null) 
{ 
throw new InvalidOperationException("NHibernate configuration is null."); 
} 

config.AddAssembly("My.Assembly.Here"); 
factory = config.BuildSessionFactory(); 

if (factory==null) 
{ 
throw new InvalidOperationException("Call to Configuration.BuildSessionFactory() returned null."); 
} 

session = factory.OpenSession(); 

if (session==null) 
{ 
throw new InvalidOperationException("Call to factory.OpenSession() returned null."); 
} 

return session; 
    } 
} 

Daj mi znać, jeśli to pomaga.

0

Dziękujemy! Jest to pomocne, ale szukam czegoś, co jest bardziej wytrzymałe.

Na przykład, na stronie NH (http://hibernate.org/363.html#A9) znajduje się artykuł autorstwa Andrew Mayorova, który publikuje trzy pliki, takie jak ten (http://nhibernate.sourceforge.net/contrib/Wiki_AndrewMayorovAspNet.zip).

Chodzi o to, że nie przynosi to zbytniej pomocy. Nie jestem do końca pewny, jak go właściwie wykorzystać. Próbowałem niektórych rzeczy, ale wpadłem w kłopoty.

Ktoś ma coś, co używa tego lub podobnego?

+1

Co masz na myśli mówiąc "solidne"? Czy możesz bardziej precyzyjnie określić, czego brakuje? Co próbowałeś? I jakie kłopoty napotkaliście? Walczyłem, kiedy zaczynałem od NHibernate, więc chciałbym pomóc, jeśli to w ogóle możliwe. –

17

Zapoznaj się z Billy McCafferty's work. Jego wcześniejsza wersja miała pewne ograniczenia, musisz poprawić obsługę błędów związanych z zamykaniem i płukaniem i nie jestem pewien, czy mam rację, ale opowiem, jak zmodyfikowałem jego rzeczy.

Billy pracuje również nad nowym środowiskiem, które używa MVC & nHilbernate o nazwie S #arp Architechure, którego aktualnie używam, i do tej pory tak dobrze.

W każdym razie oto moja zmodyfikowana wersja jego kodu. Nie robię żadnych gwarancji dokładności ani kompletności i korzystasz z nich na własne ryzyko. Jeśli używasz tego, upewnij się, że zamknąłeś sesję. Jeśli masz jakieś pytania, wyślij mi e-mail [joshua] [dot] [berke] w [gmail ... znasz resztę].

/// <summary> 
/// Handles creation and management of sessions and transactions. It is a singleton because 
/// building the initial session factory is very expensive. Inspiration for this class came 
/// from Chapter 8 of Hibernate in Action by Bauer and King. Although it is a sealed singleton 
/// you can use TypeMock (http://www.typemock.com) for more flexible testing. 
/// </summary> 
public sealed class NHibernateSessionManager 
{ 
    private const string DefaultConfigFile = "DefaultAppWeb.Config"; 
    private static readonly object _syncRoot = new object(); 
    #region Thread-safe, lazy Singleton 

/// <summary> 
/// This is a thread-safe, lazy singleton. See http://www.yoda.arachsys.com/csharp/singleton.html 
/// for more details about its implementation. 
/// </summary> 
public static NHibernateSessionManager Instance 
{ 
    get 
    { 
     return Nested.NHibernateSessionManager; 
    } 
} 

/// <summary> 
/// Private constructor to enforce singleton 
/// </summary> 
private NHibernateSessionManager() { } 

/// <summary> 
/// Assists with ensuring thread-safe, lazy singleton 
/// </summary> 
private class Nested 
{ 
    static Nested() { } 
    internal static readonly NHibernateSessionManager NHibernateSessionManager = 
     new NHibernateSessionManager(); 
} 

#endregion 

/// <summary> 
/// This method attempts to find a session factory stored in <see cref="sessionFactories" /> 
/// via its name; if it can't be found it creates a new one and adds it the hashtable. 
/// </summary> 
/// <param name="sessionFactoryConfigPath">Path location of the factory config</param> 
private ISessionFactory GetSessionFactoryFor(string sessionFactoryConfigPath) 
{ 
    Check.Require(!string.IsNullOrEmpty(sessionFactoryConfigPath), 
     "sessionFactoryConfigPath may not be null nor empty"); 

    // Attempt to retrieve a stored SessionFactory from the hashtable. 
    ISessionFactory sessionFactory;// = (ISessionFactory)sessionFactories[sessionFactoryConfigPath]; 

    // try and get a session factory if we don't find one create it 
    lock (_syncRoot) 
    { 
     if (!sessionFactories.TryGetValue(sessionFactoryConfigPath, out sessionFactory)) 
     { 
      Configuration cfg = new Configuration(); 
      if (sessionFactoryConfigPath != DefaultConfigFile) 
      { 
       Check.Require(File.Exists(sessionFactoryConfigPath), 
        "The config file at '" + sessionFactoryConfigPath + "' could not be found"); 
       cfg.Configure(sessionFactoryConfigPath); 


      } 
      else 
      { 
       cfg.Configure(); 
      } 


      // Now that we have our Configuration object, create a new SessionFactory 
      sessionFactory = cfg.BuildSessionFactory(); 


      Check.Ensure(sessionFactory != null, "sessionFactory is null and was not built"); 
      sessionFactories.Add(sessionFactoryConfigPath, sessionFactory); 
     } 
    } 



    return sessionFactory; 
} 

/// <summary> 
/// Allows you to register an interceptor on a new session. This may not be called if there is already 
/// an open session attached to the HttpContext. If you have an interceptor to be used, modify 
/// the HttpModule to call this before calling BeginTransaction(). 
/// </summary> 
public void RegisterInterceptorOn(string sessionFactoryConfigPath, IInterceptor interceptor) 
{ 
    ISession session = (ISession)ContextSessions[sessionFactoryConfigPath]; 

    if (session != null && session.IsOpen) 
    { 
     throw new CacheException("You cannot register an interceptor once a session has already been opened"); 
    } 

    GetSessionFrom(sessionFactoryConfigPath, interceptor); 
} 

public ISession GetSessionFrom(string sessionFactoryConfigPath) 
{ 
    return GetSessionFrom(sessionFactoryConfigPath, null); 
} 
/// <summary> 
/// Gets or creates an ISession using the web/app config file. 
/// </summary> 
/// <returns></returns> 
public ISession GetSessionFrom() 
{ 
    return GetSessionFrom(DefaultConfigFile, null); 
} 
/// <summary> 
/// Gets a session with or without an interceptor. This method is not called directly; instead, 
/// it gets invoked from other public methods. 
/// </summary> 
private ISession GetSessionFrom(string sessionFactoryConfigPath, IInterceptor interceptor) 
{ 
    var allSessions = ContextSessions; 
    ISession session = null; 
    if (!allSessions.TryGetValue(sessionFactoryConfigPath, out session)) 
    { 
     if (interceptor != null) 
     { 
      session = GetSessionFactoryFor(sessionFactoryConfigPath).OpenSession(interceptor); 
     } 
     else 
     { 
      session = GetSessionFactoryFor(sessionFactoryConfigPath).OpenSession(); 
     } 

     allSessions[sessionFactoryConfigPath] = session; 
    } 

    //session.FlushMode = FlushMode.Always; 

    Check.Ensure(session != null, "session was null"); 

    return session; 
} 

/// <summary> 
/// Flushes anything left in the session and closes the connection. 
/// </summary> 
public void CloseSessionOn(string sessionFactoryConfigPath) 
{ 
    ISession session; 
    if (ContextSessions.TryGetValue(sessionFactoryConfigPath, out session)) 
    { 
     if (session.IsOpen) 
     { 
      session.Flush(); 
      session.Close(); 
     } 
     ContextSessions.Remove(sessionFactoryConfigPath); 

    } 

} 

public ITransaction BeginTransactionOn(string sessionFactoryConfigPath) 
{ 
    ITransaction transaction; 

    if (!ContextTransactions.TryGetValue(sessionFactoryConfigPath, out transaction)) 
    { 
     transaction = GetSessionFrom(sessionFactoryConfigPath).BeginTransaction(); 
     ContextTransactions.Add(sessionFactoryConfigPath, transaction); 
    } 

    return transaction; 
} 

public void CommitTransactionOn(string sessionFactoryConfigPath) 
{ 

    try 
    { 
     if (HasOpenTransactionOn(sessionFactoryConfigPath)) 
     { 
      ITransaction transaction = (ITransaction)ContextTransactions[sessionFactoryConfigPath]; 

      transaction.Commit(); 
      ContextTransactions.Remove(sessionFactoryConfigPath); 
     } 
    } 
    catch (HibernateException he) 
    { 
     try 
     { 
      RollbackTransactionOn(sessionFactoryConfigPath); 
     } 
     finally 
     { 
      throw he; 
     } 
    } 
} 

public bool HasOpenTransactionOn(string sessionFactoryConfigPath) 
{ 
    ITransaction transaction; 
    if (ContextTransactions.TryGetValue(sessionFactoryConfigPath, out transaction)) 
    { 

     return !transaction.WasCommitted && !transaction.WasRolledBack; 
    } 
    return false; 
} 

public void RollbackTransactionOn(string sessionFactoryConfigPath) 
{ 

    try 
    { 
     if (HasOpenTransactionOn(sessionFactoryConfigPath)) 
     { 
      ITransaction transaction = (ITransaction)ContextTransactions[sessionFactoryConfigPath]; 

      transaction.Rollback(); 
     } 

     ContextTransactions.Remove(sessionFactoryConfigPath); 
    } 
    finally 
    { 

     ForceCloseSessionOn(sessionFactoryConfigPath); 
    } 
} 

/// <summary> 
/// Since multiple databases may be in use, there may be one transaction per database 
/// persisted at any one time. The easiest way to store them is via a hashtable 
/// with the key being tied to session factory. If within a web context, this uses 
/// <see cref="HttpContext" /> instead of the WinForms specific <see cref="CallContext" />. 
/// Discussion concerning this found at http://forum.springframework.net/showthread.php?t=572 
/// </summary> 
private Dictionary<string, ITransaction> ContextTransactions 
{ 
    get 
    { 
     if (IsInWebContext()) 
     { 
      if (HttpContext.Current.Items[TRANSACTION_KEY] == null) 
       HttpContext.Current.Items[TRANSACTION_KEY] = new Dictionary<string, ITransaction>(); 

      return (Dictionary<string, ITransaction>)HttpContext.Current.Items[TRANSACTION_KEY]; 
     } 
     else 
     { 
      if (CallContext.GetData(TRANSACTION_KEY) == null) 
       CallContext.SetData(TRANSACTION_KEY, new Dictionary<string, ITransaction>()); 

      return (Dictionary<string, ITransaction>)CallContext.GetData(TRANSACTION_KEY); 
     } 
    } 
} 

/// <summary> 
/// Since multiple databases may be in use, there may be one session per database 
/// persisted at any one time. The easiest way to store them is via a hashtable 
/// with the key being tied to session factory. If within a web context, this uses 
/// <see cref="HttpContext" /> instead of the WinForms specific <see cref="CallContext" />. 
/// Discussion concerning this found at http://forum.springframework.net/showthread.php?t=572 
/// </summary> 
private Dictionary<string, ISession> ContextSessions 
{ 
    get 
    { 
     if (IsInWebContext()) 
     { 
      if (HttpContext.Current.Items[SESSION_KEY] == null) 
       HttpContext.Current.Items[SESSION_KEY] = new Dictionary<string, ISession>(); 

      return (Dictionary<string, ISession>)HttpContext.Current.Items[SESSION_KEY]; 
     } 
     else 
     { 
      if (CallContext.GetData(SESSION_KEY) == null) 
       CallContext.SetData(SESSION_KEY, new Dictionary<string, ISession>()); 

      return (Dictionary<string, ISession>)CallContext.GetData(SESSION_KEY); 
     } 
    } 
} 

private bool IsInWebContext() 
{ 
    return HttpContext.Current != null; 
} 

private Dictionary<string, ISessionFactory> sessionFactories = new Dictionary<string, ISessionFactory>(); 
private const string TRANSACTION_KEY = "CONTEXT_TRANSACTIONS"; 
private const string SESSION_KEY = "CONTEXT_SESSIONS"; 

public bool HasOpenTransactionOn() 
{ 
    return HasOpenTransactionOn(DefaultConfigFile); 
} 

public void CommitTransactionOn() 
{ 
    CommitTransactionOn(DefaultConfigFile); 
} 

public void CloseSessionOn() 
{ 
    CloseSessionOn(DefaultConfigFile); 
} 

public void ForceCloseSessionOn() 
{ 
    ForceCloseSessionOn(DefaultConfigFile); 

} 

public void ForceCloseSessionOn(string sessionFactoryConfigPath) 
{ 
    ISession session; 
    if (ContextSessions.TryGetValue(sessionFactoryConfigPath, out session)) 
    { 
     if (session.IsOpen) 
     { 

      session.Close(); 
     } 
     ContextSessions.Remove(sessionFactoryConfigPath); 

    } 
} 

public void BeginTransactionOn() 
{ 
    this.BeginTransactionOn(DefaultConfigFile); 
} 

public void RollbackTransactionOn() 
{ 
    this.RollbackTransactionOn(DefaultConfigFile); 
} 

}

+0

Dobre rzeczy. Używając NH 3.2, działa świetnie z jednym modem: musiałem zmienić 'HasOpenTransactionOn' by użyć' transaction.IsActive'. [Oto dlaczego] (http://stackoverflow.com/a/1007633/612265). –

+0

Ohh nice! Dzięki wielkie – JoshBerke

5

W przeszłości odniosłem wielki sukces, korzystając z modułów wsparcia NHibernate Spring.NET. Zobacz http://www.springframework.net/downloads/Spring.Data.NHibernate/. Powinieneś być w stanie użyć modułu OpenSessionInView i wydłużyć swoje DAO z DAibernateSupport DAO, aby uzyskać pełną obsługę zarządzania open session in view pattern. Dodatkowo, mimo że nigdy tego nie próbowałem, powinieneś być w stanie użyć powyższych ram, nawet jeśli zrezygnujesz z resetowania ofert Spring.NET (mianowicie IoC i AOP).

2

Napisałem numer blog post w tym miejscu, w którym korzystam z implementacji zarządzanej sieci w kontekście obsługi sesji kontekstowych. Może tego właśnie szukasz?

1

dwie propozycje:

  • Jeffrey Palermo HybridSessionBuilder (jeffreypalermo.com/blog/use-this-nhibernate-wrapper-to-keep-your-repository-classes-simple)
  • Zobacz przykłady kodu (konkretnie zobaczyć Sesja 13) w lecie NHibernate (www.summerofnhibernate.com)
0

może chcesz rozważyć swoją DAL mniej dotyczy zarządzania sesjami NHibernate wykorzystując NHibernate.Burrow (lub realizuje podobny wzór samemu).

"NHibernate.Burrow to lekkie oprogramowanie pośredniczące opracowane w celu obsługi aplikacji .Net przy użyciu NHibernate, zapewniając zaawansowane i inteligentne zarządzanie sesjami/transakcjami oraz inne ułatwienia."

Jeśli zdecydujesz się toczyć własne istnieją pewne użyteczne linki na dole tej strony:

Użyteczna wyszukiwarka google termin będzie „NHibernate Session Management” i „Sesje z kontekstu” ...

Nie brakuje pomysłów - można powiedzieć, że jest ich zbyt wiele, mam nadzieję, że opinia zacznie ciążyć wokół Nory lub czegoś podobnego ...

Powiązane problemy