Laden...

NHibernate bei ASP.NET nicht effizient?

Erstellt von carom vor 12 Jahren Letzter Beitrag vor 12 Jahren 1.499 Views
C
carom Themenstarter:in
90 Beiträge seit 2008
vor 12 Jahren
NHibernate bei ASP.NET nicht effizient?

Hallo!

Gerade tätige ich meine ersten Schritte mit NHibernate (zusammen mit SQL Server 2010), Ziel ist, eine ASP.NET Anwendung darauf umzustellen. Bisher werden dort noch mühevoll Objekte manuell mittels SQL-Statements persistiert, damit soll nun Schluss sein. Meine Wahl fiel auf NHibernate, da ich früher mal mittels dem original Hibernate und einer Java Desktopanwendung zu tun hatte.
Ich wusste von damals noch, dass das Instantiieren einer Session eine ziemlich teure Aktion ist und man deshalb ein Singleton benutzt, um eine erzeugte Session wiederverwenden zu können. Allerdings: das damals war wie gesagt eine Desktopapplikation, bei ASP.NET fällt mir da gerade ein doofes Problem auf: bei jeder Seitenanfrage wird logischerweise ein neues Objekt im Singleton erstellt, das Muster verliert also stark an Effizienz. Bei ASP.NET Seiten mit nur einem Query ist der Unterschied, ob man ein Singleton einsetzt oder nicht, praktisch null.

Habe jetzt mal nachgemessen, reproduzierbar: satte 1,8 Sekunden braucht die erste Anfrage auf das Singleton, alle weiteren nur noch ca. 0.002 Sekunden. Wohlgemerkt die reine DB-Abfrage, der Seitenaufbau drumherum nicht beachtet. Also wenn ich jetzt nicht auf dem Schlauch stehe, dann wird, abstrakt gesagt, jeder Klick eines Users auf der Page einfach so 1,8 Sekunden länger dauern (sofern Hibernate involviert ist). Stimmt das oder liege ich da falsch? *

Gibt es da ein Mechanismus, mit dem man da besser aufgestellt ist, kann man evt. eine Session zuverlässig über mehrere Requests mitnehmen? Falls nein, was für Alternativen könnt ihr mir nennen?
Es wäre mir sogar wert, die Technlogie zur Persistenz komplett zu tauschen, also zum Beispiel weg von SQL, wenn obiges Problem alle OR-Mapper gemeinsam haben. Einzige Bedingung: es muss sich nach wie vor so anfühlen wie ORM oder eine richtige Objektdatenbank, sprich Objekte speichern und lesen, die Arbeit dahinter sollte mich nicht beschäftigen müssen.

Vielen Dank!

*was ich damit meinte: jeder Klick auf einen Link, der eine neue Seite anfordert, triggert ein neue session.. das Laden der Seite verzögert sich um 1,8s. Damit würde das Erstellen der session länger dauern als bisher die Zeit vom Klick des Users bis zum vollständigen Laden der Seite.

16.835 Beiträge seit 2008
vor 12 Jahren

Hallo,

wenn es sich um eine MVC Anwendung handelt, kann ich die Entscheidung auf NHibernate nicht nachvollziehen, da MVC Hand in Hand mit dem EntityFramework arbeitet; und dafür auch geeignete Schnittstellen hat.
NHibernate wäre hier also pauschal gesagt die falsche Wahl.

Sollte dies nicht der Fall sein, so vergiss den Post. Uu NHibernate kann ich nichts sagen.

Dass die ersten Anfragen einer Webanwendung immer länger dauern ist normal: hier werden die Seiten kompiliert. Alle weiteren Abfragen rennen nicht mehr durch den Compiler, sondern werden aus dem Cache geladen.
Dies hat aber mit NHibernate nichts zutun und ist ein normales Verhalten.

C
carom Themenstarter:in
90 Beiträge seit 2008
vor 12 Jahren

Es handelt sich um "normales" ASP.NET ohne MVC Framework.

Zu deinem letzten Absatz: das ist soweit klar, ja. Ich meinte aber nicht den aller ersten Request auf eine Seite, sondern alle Requests auf eine Seite.
In Hibernate gibt es ein Singleton. Wenn man sich eine session von diesem holt, dann dauert das beim ersten mal gut 2 Sekunden - danach geht's schneller, weil das Singleton die bereits erzeugte sessionfactory-Instanz wiederverwendet. In Desktopappliaktionen funktioniert das prima. In ASP.NET hingegen werden ja für jeden Request teilweise neue Objekte erzeugt, und somit auch ein komplett neues Singleton mit neuer sessionfactory. Statt wie auf dem Desktop jetzt einmal die 2 Sekunden warten zu müssen und dann für immer ein und die selbe sessionfactory nutzen zu können, wartet man bei jedem Seitenrequest wieder 2 Sekunden weil Instanzen aus vorherigen Requests verloren gingen.

2.891 Beiträge seit 2004
vor 12 Jahren

Was genau hast du da als Singleton?
Erzeugst du in deinem Ursprungsfall die Session oder auch die SessionFactory jedesmal neu?

C
carom Themenstarter:in
90 Beiträge seit 2008
vor 12 Jahren

Eine neue Factory. Aber brauche ich nicht zwingend bei jedem neuen Request eine neue Factory? Wenn ich nicht falsch liege, dann ist die Factory beim nächsten Request weg und muss wieder neu erzeugt werden um an eine Session zu kommen, man kann ein- und dieselbe Factory ja nicht für mehrere Requests verwenden... oder etwa doch?

private static ISessionFactory SessionFactory;

        private static void OpenSession()
        {
            Configuration configuration = new Configuration();
            configuration.AddAssembly(Assembly.GetCallingAssembly());
            SessionFactory = configuration.BuildSessionFactory();
        }

        public static ISession GetCurrentSession()
        {
            if (SessionFactory == null)
                NHibernateHelper.OpenSession();

            return SessionFactory.OpenSession();
        }

        public static void CloseSessionFactory()
        {
            if (SessionFactory != null)
                SessionFactory.Close();
        }
656 Beiträge seit 2008
vor 12 Jahren

Das Erzeugen der SessionFactory ist teuer, nicht das Erzeugen der Session.

C
carom Themenstarter:in
90 Beiträge seit 2008
vor 12 Jahren

Das Erzeugen der SessionFactory ist teuer, nicht das Erzeugen der Session.

Sorry, falls ich mich im ersten Post ungenau ausgedrückt habe. Ja, das ist mir bewusst, und dennoch brauche ich bei jedem Seitenaufruf eine neue Factory, oder nicht?

2.891 Beiträge seit 2004
vor 12 Jahren

Und die SessionFactory musst du nur einmal - nicht bei jedem Request - erstellen.

Du brauchst nicht pro Request eine neue Session Factory. So, wie du das machst, scheint das richtig zu sein (bis auf die Benennung der Methoden). Da wird eine SessionFactory pro Lebenszeit deiner Anwendung erstellt.

Zum Thema NHibernate oder nicht: Wenn du (einzig) auf den MS SQL Server zugreifen möchtest, würde ich immer zu LINQ2SQL (meinetwegen auch EntityFramework) raten. Macht sich einfacher und die Zusammenarbeit zwischen O/R-Mapper und Datenbank ist einfach besser.

C
carom Themenstarter:in
90 Beiträge seit 2008
vor 12 Jahren

Erstmal danke an alle.

Und die SessionFactory musst du nur einmal - nicht bei jedem Request - erstellen.

Du brauchst nicht pro Request eine neue Session Factory. So, wie du das machst, scheint das richtig zu sein (bis auf die Benennung der Methoden). Da wird eine SessionFactory pro Lebenszeit deiner Anwendung erstellt.

Und genau damit habe ich ein Denkproblem. Wenn wir von "normalen" Anwendungen reden, also Konsolen-, Swinganwendungen, oder Serverapplikationen und so weiter, dann kann ich das natürlich nachvollziehen. Die von dir angesprochene Lebenszeit einer Anwendung geht los beim Start des Programms und endet, wenn der User auf das "X" drückt, und sei es Stunden oder Tage später.

Aber was ist die Lebenszeit einer ASP.NET Anwendung? Vielleicht bin ich zu stark von PHP geprägt, aber mit meinem bisherigen Verständnis beginnt die Lebenszeit mit dem HTTP-Request des Benutzers (sprich, er ruft mycsharp.de im Browser auf) und endet wenige (zehntel-) Sekunden später, nämlich dann wenn die HTTP-Response an den Benutzer zurückgeht. In der Zwischenzeit wird alles erzeugt und alles verworfen. Klickt der User auf der mycsharp-Startseite jetzt den Link /wbb2/forum, dann beginnt die Lebenszeit der Anwendung von vorne, nur um kruze Zeit später wieder zu Enden.

Und während in der Desktopanwendung mein Singleton lebt, bis der Nutzer das X drückt, so lebt es in ASP.NET doch nur von Request zu Request - das dachte ich bisher immer. Vielleicht ist mein Problem jetzt klarer.

161 Beiträge seit 2007
vor 12 Jahren

Die Anwendung wird gestartet beim ersten Request. Dort wird dann auch die SessionFactory erzeugt (was zur Folge hat das der erste Request in der Regel länger dauert).

Die Anwendung lebt dann so lange bis der Application Pool recycled wird, sie manuell gestoppt wird oder nach einer definierten Zeit der Inaktivität.

In der Zwischenzeit erhälst du für jeden Request "nur" eine neue Session.

Zumindest soweit meine Erinnerung an das Thema.

"Eine wirklich gute Idee erkennt man daran,
dass ihre Verwirklichung von vorneherein ausgeschlossen erscheint."
(Albert Einstein)

2.891 Beiträge seit 2004
vor 12 Jahren

Siehe auch ASP.NET-Lebenszyklus.