2011-01-15 6 views
2

Ich habe eine Webanwendung mithilfe von Asp.NET-Webform, NHibernate für den Zugriff auf Sql Server 2008-Datenbank und StructureMap als IOC-Container erstellt.NHibernate StructureMap ASP.NET-Webformular System.OutOfMemoryException

Alles scheint gut zu funktionieren, da nur wenige Benutzer es verwenden;

System.OutOfMemoryException

Ich heruntergeladen redgate Ameisen Suite: wenn Benutzer Zahl steigt Webapp Abstürze mit diesem Fehler (wir 10+ Nutzer sagen kann) die Performance-Tool sagt, dass die maximale CPU-Zeit für eine GetAll in NHibernate createSessionFactory ist anfordern.

Das ist mein NHibernateHelper Objekt:

public static NHibernate.ISessionFactory _sessionFactory; 
public static NHibernate.ISessionFactory createSessionFactory() 
{ 
try 
{ 
    if (_sessionFactory == null) 
    { 
    return 
     FluentNHibernate.Cfg.Fluently.Configure() 
     .Database 
     (
     FluentNHibernate 
     .Cfg.Db.MsSqlConfiguration.MsSql2008 
     .ConnectionString 
     (
      c => c 
      .Server(ConfigurationManager.DbConnectionValue.Server) 
      .Username(ConfigurationManager.DbConnectionValue.User) 
      .Password(ConfigurationManager.DbConnectionValue.Password) 
      .Database(ConfigurationManager.DbConnectionValue.Database) 
     ) 
     .ProxyFactoryFactory("NHibernate.ByteCode.LinFu.ProxyFactoryFactory,NHibernate.ByteCode.LinFu") 
     ) 
     .Mappings 
     (
     m => m.FluentMappings.AddFromAssemblyOf<Repository.IRepositoryBlocco>() 
     ) 

     .BuildSessionFactory(); 
    } 
    else 
    return _sessionFactory; 
} 
catch (Exception ex) 
{ 
    throw ex; 
} 
} 

Dies ist die Art, wie ich Daten von db lesen:

public IList<DomainModel.Model.Variabile> GetAll() 
{ 
    try 
    { 
    var session_factory = NHibernateHelper.createSessionFactory(); 

    using (var session = session_factory.OpenSession()) 
    { 
     using (var transaction = session.BeginTransaction()) 
     { 
     var query = session.Linq<DomainModel.Model.Variabile>() 
      .OrderBy(v => v.ordine); 

     return query.ToList(); 
     } 
    } 
    } 
    catch (Exception ex) 
    { 
    throw ex; 
    } 
} 

Bin ich keine Fehler gemacht? Könnte es die sein, die OutOfMemoryException provoziert? Mit freundlichen Grüßen

+1

Sie weisen _sessionFactory-Variable niemals der soeben erstellten Factory zu, so dass sie jedes Mal eine neue Session-Factory erstellt, wenn –

+0

funktioniert! Thx viel – frabiacca

Antwort

2

Es sieht aus wie die Session in jedem Aufruf der GetAll Methode erstellt wird. Das Erstellen der SessionFactory ist eine teure Operation. Ich würde einer der beiden folgenden Optionen folgen:

Erstellen Sie die SessionFactory in der Startmethode der Anwendung. Dies wäre in der Datei Global.asax.cs. Dann aussetzen eine statische öffentliche Eigenschaft für das Session in der globalen asax Klasse, die von einem beliebigen Verfahren zugegriffen werden konnte, wie so

Global.SessionFactory.OpenSession 

Die andere Möglichkeit wäre, eine Repository Fabrik oder eine Repository Provider-Klasse zu haben. Dies hätte einen Konstruktor, der die Verbindungszeichenfolge aufnehmen würde. Basierend auf den Konstruktorparametern wird die SessionFactory erstellt und eine Instanz der Repository-Klasse erstellt. Die Repository-Klasse würde alle Ihre Getxxx-Methoden enthalten. So wäre das so etwas wie

public interface IRepositoryFactory 
{ 
    IRepository GetRepository(); 
} 

public interface IRepository:IDispose 
{ 
    IEnumerable<T> Getxxx<T>(); 

} 

public class RepositoryFactory:IRepositoryFactory 
{ 
    private string _connectionString; 
    public RepositoryFactory(string connectionString) 
    { 
      _connectionString=connectionString; 
    } 

    public IRepository GetRepository() 
    { 
     //use the connection string and fluently build SessionFactory 
     return new Repository(SessionFactory.OpenSession()); 
    }  
} 

public class Repository:IRepository 
{ 
    private ISession _session; 
    public Repository(ISession session) 
    { 
     _session=session; 
    } 

    public IEnumerable<T> Getxxx<T>() 
    { 
     return _session.Query<T>(); 
    } 

    public void Dispose() 
    { 
    //dispose session and any other disposables 
    } 
} 

Und Sie können StructureMap konfigurieren Instanzen von

RepositoryFactory bereitzustellen
For<IRepositoryFactory>.Use<RepositoryFactory>().Ctor<string>.EqualToAppSetting("connStr"); 

Jetzt können Sie SM sagen Sie Instanz von RepositoryFactory geben mit dem Sie eine Repository-Instanz erhalten und mache alle Getxx-Anrufe.

Hoffe, das hilft!

+0

Ich werde es testen. Danke für den Vorschlag :) – frabiacca

1

Zuerst erstellen Sie eine neue Session-Factory für jeden Anruf. Dies ist eine teure Operation. Sie sollten über eine Sitzungsfactory für Ihre App verfügen, die Sitzungen nach Bedarf erstellt. An zweiter Stelle von allem, was Sie folgende nicht die Einheit der Arbeitsmuster, die von NHibernate empfohlen:

http://nhforge.org/wikis/patternsandpractices/nhibernate-and-the-unit-of-work-pattern.aspx

+1

bearbeiten: vergiss. es ist das. Er weist Variablen niemals zu. –