UPDATE: if you came here looking for an english post I'm sorry but I haven't had time to translate it yet. Anyway all you need to do is just copy and paste the code you see through the post itself to make it work. Just let me know if you experience any issues.
Furhermore, on the Db4o forum there's an interesting post in which I proposed and discussed this same solution with Db4o creators. Here's the link: http://forums.db4o.com/forums/10381/ShowPost.aspx
Premetto che sono abbastanza nuovo nell'utilizzo di Db4o, quindi come al solito accetto suggerimenti e correzioni relativamente alla soluzione che segue.
Cercando di creare un'applicazione ASP.NET semplice che si basasse su questo odbms mi sono subito ritrovato ad affrontare problemi che il pur ben fatto tutorial che è possibile scaricare assieme alla distribuzione non è in grado di chiarire.
Utilizzando Db4o con ASP.NET sorgono almeno due problemi che in ambiente desktop non sono presenti:
- è necessario avere un ObjectContainer che stia aperto almeno per l'intera durata della richiesta.
Ci si potrebbe chiedere perchè... al momento non ho incontrato altri problemi relativamente all'apertura e chiusura immediata di un ObjectContainer se non che, ad esempio, se voglio eseguire una query e poi utilizzarne i risultati per visualizzarli in una pagina aspx, NON POSSO aver già chiuso l'ObjectContainer, e poichè è assurdo delegarne apertura e chiusura alla pagina stessa, è necessario trovare un altro meccanismo che lo tenga aperto ALMENO per la durata della richiesta.
- gestire transazioni concorrenti.
Ricordando come era stata realizzata una soluzione simile in vari post su NHibernate, ed essendo il problema abbastanza simile, ho creato la mia soluzione utilizzando una classe che implementasse l'interfaccia IHttpModule.
Per risolvere il primo problema ho quindi pensato di creare un oggetto ObjectContainer quando viene richiesto per la prima volta, inserirlo in HttpContext.Current.Items in modo da poterne ottenere un riferimento durante l'intera durata della richiesta, e di chiuderlo alla fine della richiesta.
Per risolvere il secondo problema, invece, ho delegato l'apertura del file .yap ad un ObjectServer statico, che è quindi lo stesso per tutte le richieste.
Ora il codice:
using System;
using System.Configuration;
using System.Web;
using com.db4o;
namespace MioProgetto.DataAccess
{
///
/// Summary description for Db4oHttpModule.
///
public class Db4oHttpModule : IHttpModule
{
internal static readonly string KEY_DB4O_FILE_NAME = "db4oFileName";
internal static readonly string KEY_DB4O_CLIENT = "db4oClient";
private static ObjectServer objectServer = null;
public void Init(HttpApplication application)
{
application.EndRequest += new EventHandler(Application_EndRequest);
}
internal static ObjectContainer Client
{
get
{
HttpContext context = HttpContext.Current;
ObjectContainer objectClient = context.Items[KEY_DB4O_CLIENT] as ObjectContainer;
if(objectClient == null)
{
objectClient = Server.OpenClient();
context.Items[KEY_DB4O_CLIENT] = objectClient;
}
return objectClient;
}
}
private static ObjectServer Server
{
get
{
HttpContext context = HttpContext.Current;
if(objectServer == null)
{
string yapFilePath = context.Server.MapPath(ConfigurationSettings.AppSettings[KEY_DB4O_FILE_NAME]);
objectServer = Db4o.OpenServer(yapFilePath, 0);
}
return objectServer;
}
}
public static string HashCodes
{
get { return "Server HashCode: " + Server.GetHashCode() + " Client HashCode: " + Client.GetHashCode(); }
}
private void Application_EndRequest(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
HttpContext context = application.Context;
ObjectContainer objectClient = context.Items[KEY_DB4O_CLIENT] as ObjectContainer;
if(objectClient != null)
{
objectClient.Close();
objectClient = null;
context.Items[KEY_DB4O_CLIENT] = null;
}
}
public void Dispose()
{
if(objectServer != null)
{
objectServer.Close();
objectServer = null;
}
}
}
}
Come è possibile notare ho anche inserito una proprietà statica HashCodes che ritorna una stringa contenente gli HashCodes del Server e del Client, più che altro a scopo di debugging, per verificare che il server è sempre lo stesso ad ogni richiesta - garantendo quindi che la concorrenza venga gestita in modo corretto - e che il client invece rispetta il pattern one-per-request.
Ora naturalmente è necessario registrare il modulo http nel web.config:
<httpModules>
type="MioProgetto.DataAccess.Db4oHttpModule, MioProgetto.DataAccess"
name="Db4oHttpModule" />
</httpModules>
Oltre a questo è necessario specificare il percorso del file .yap:
<appSettings>
key="db4oFileName" value="~/CartellaConPermessiDiScrittura/database.yap" />
</appSettings>
Per utilizzarlo, infine, è sufficiente ottenere il riferimento all'ObjectContainer tramite la proprietà statica Client, ad esempio:
public static IList RetrieveAll()
{
return Db4oHttpModule.Client.Get(new MiaClasseEntity());
}
Spero possa servire!
powered by IMHO 1.3