2017-10-02 1 views
1

Ich habe ein .NET MVC Webapi mit Nhibernate, um mehrere Informix-Datenbanken zu verbinden, ich verwende Repository und Arbeitseinheit Muster..NET Nhibernate Sitzung macht Speicherverbrauch wächst

Das Problem ist, wenn send multiple Anfrage an mvc Web API, Speicher des Servers wächst und macht meine Website stoppen.

Dies ist die Einheit der Arbeitsklasse:

public interface IUnitOfWorkNH: IDisposable 
{ 
    void BeginTransaction(); 
    void Commit(); 
} 

public class UnitOfWorkNH : IUnitOfWorkNH 
{ 
    private ISessionFactory _sessionFactory; 
    private ITransaction _transaction; 

    public ISession Session { get; private set; } 

    public UnitOfWorkNH(string connection) 
    { 
     string stringConnection = ConfigurationManager.AppSettings["NH_DSN"].ToString(); 
     if (!string.IsNullOrEmpty(connection)) 
     { 
      stringConnection = connection; 
     } 
     _sessionFactory = Fluently.Configure() 
      .Database(OdbcConfiguration.InformixODBC.ConnectionString(stringConnection) 
      .Driver<NHibernate.Driver.OdbcDriver>() 
      .Dialect<NHibernate.Dialect.InformixDialect>() 
      //.ShowSql() 
     ) 
      .Mappings(m => 
         m.FluentMappings 
          .AddFromAssemblyOf<clsCiaMap>()) 
      .ExposeConfiguration(cfg => new SchemaExport(cfg) 
              .Create(false, false)) 

      .BuildSessionFactory(); 

     Session = _sessionFactory.OpenSession(); 
    }   

    public void BeginTransaction() 
    { 
     _transaction = Session.BeginTransaction(); 
    } 

    public void Commit() 
    { 
     try 
     { 
      // commit transaction if there is one active 
      if (_transaction != null && _transaction.IsActive) 
       _transaction.Commit(); 
     } 
     catch 
     { 
      // rollback if there was an exception 
      if (_transaction != null && _transaction.IsActive) 
       _transaction.Rollback(); 

      throw; 
     } 
     finally 
     { 
      Session.Dispose(); 
     } 
    } 

    public void Rollback() 
    { 
     try 
     { 
      if (_transaction != null && _transaction.IsActive) 
       _transaction.Rollback(); 
     } 
     finally 
     { 
      Session.Dispose(); 
     } 
    } 

    public void Dispose() 
    { 
     if (this._transaction != null) 
     { 
      this._transaction.Dispose(); 
      this._transaction = null; 
     } 

     if (this.Session != null) 
     { 
      this.Session.Dispose(); 
      Session = null; 
     } 
     this._sessionFactory.Dispose(); 
     this._sessionFactory = null; 
    } 
} 

Dies ist die Repository-Klasse:

public interface IRepository<T> where T : class 
{ 
    List<T> GetAll(); 
    T GetById(int id); 
    T GetById(string id); 
    T GetById(T id); 
    void Save(T entity); 
    void Delete(T entity); 
} 

public class RepositoryNH<T> : IRepository<T> where T : class 
{ 
    ISession _session; 


    public RepositoryNH(ISession session) 
    { 
     _session = session; 
    } 

    public ISession Session { get { return _session; } } 

    public List<T> GetAll() 
    { 
     return Session.QueryOver<T>().List().ToList(); 
    } 

    public T GetById(int id) 
    { 
     return _session.Get<T>(id); 
    } 

    public T GetById(string id) 
    { 
     return Session.Get<T>(id); 
    } 

    public T GetById(T id) 
    { 
     return _session.Get<T>(id); 
    } 

    public void Save(T entity) 
    { 
     Session.SaveOrUpdate(entity); 
     Session.Flush(); 
    } 

    public void Delete(T entity) 
    { 
     Session.Delete(entity); 
    } 
} 

Ich weiß nicht, wenn ich einen Fehler in diesen Klassen haben, ich brauche Hilfe.

+1

Einheit der Arbeit muss nur mit der Sitzung verknüpft sein, und es ist üblich, eine Sitzung pro Webanforderung zu verwenden. Die Sitzungsfactory muss nur eine Instanz für Ihre gesamte Anwendung sein. – Najera

+0

aber ich brauche nicht mehrere Datenbanken zu verbinden, was soll ich tun? – DanielVorph

+0

Eine Sitzungsfactory pro Datenbank, die möglicherweise mehr Kontext liefert, kann eine bessere Frage sein. – Najera

Antwort

0

Sie erstellen ein neues SessionFactory im Konstruktor der UnitOfWorkNH Klasse. Dies bedeutet, dass mehrere Instanzen der Sitzungsfactory gleichzeitig vorhanden sind. Da alle Instanzen der Sitzungsfactory in den Arbeitsspeicher geladen und nie entsorgt werden, nimmt die Speichernutzung weiter zu.

Auch Gebäude Sitzung Fabrik ist teuer Anruf. Das erneute Erstellen einer neuen Session-Factory wird die Performance stark beeinträchtigen.

Idealerweise sollte Ihre Sitzungsfabrik Singleton sein. Es sollte (beim Aufruf der Methode BuildSessionFactory()) beim Start der Anwendung erstellt werden. Dann sollte dieselbe Instanz der Sitzungsfactory verwendet werden, um ISession Instanzen unter Verwendung der _sessionFactory.OpenSession()-Anweisung zu erstellen.

Folgendes ist ein roher Code; nicht genau Singleton, kann aber hilfreich sein. Ich schlage trotzdem vor, dass Sie stattdessen die Verwendung von Singleton in Betracht ziehen.

internal static class NHSessionFactory 
{ 
    static Configuration nhConfiguration; 
    static ISessionFactory nhSessionFactory; 
    const FlushMode defaultFlushMode = FlushMode.Commit; 

    internal static ISessionFactory SessionFactory 
    { 
     get { return nhSessionFactory; } 
    } 

    internal static void CreateSessionFactory() 
    { 
     CreateSessionFactory(null); 
    } 
    internal static void CreateSessionFactory(string configFilePath) 
    { 
     CreateSessionFactory(configFilePath, defaultFlushMode); 
    } 
    internal static void CreateSessionFactory(string configFilePath, FlushMode flushMode = defaultFlushMode) 
    { 
     if(nhSessionFactory != null) 
      throw new InvalidOperationNHFacadeException("SessionFactory is already created."); 

     nhConfiguration = new Configuration(); 
     try 
     { 
      if(string.IsNullOrEmpty(configFilePath)) 
       nhConfiguration.Configure(); 
      else 
       nhConfiguration.Configure(configFilePath); 

      nhConfiguration.SessionFactory().DefaultFlushMode(flushMode); 
     } 
     catch(Exception exception) 
     { 
      throw new NHFacadeException("Failed to configure session factory.", exception); 
     } 
     try 
     { 
      nhSessionFactory = nhConfiguration.BuildSessionFactory(); 
     } 
     catch(Exception exception) 
     { 
      throw new NHFacadeException("Failed to build session factory.", exception); 
     } 
    } 

    internal static void CloseSessionFactory() 
    { 
     if(nhSessionFactory != null) 
     { 
      if(nhSessionFactory.IsClosed == false) 
       nhSessionFactory.Close(); 
      nhSessionFactory.Dispose(); 
      nhSessionFactory = null; 
     } 

     if(nhConfiguration != null) 
      nhConfiguration = null; 
    } 
} 

Bekanntmachung im Verfahren oben Code CreateSessionFactory() mir den redundanten Anruf validiert. Alles, was Sie tun müssen, ist CreateSessionFactory() beim Start der Anwendung aufrufen und CloseSessionFactory() bei Application Exit aufrufen.