A molti di voi sarà capitato di lavorare su un progetto dove è
necessario avere nel file di config una stringa di connessione
"classica" e in cui, aggiungendo un model basato su Entity
Framework, di ritrovarsi una seconda stringa "ad hoc" per il
model.
E in molti casi la prima non può essere eliminata perché magari
esiste una parte della solution non mappata (e in certi casi non
mappabile) sul datamodel appena introdotto, per cui… bisogna
tenersi entrambi le stringhe.
Nel nostro esempio abbiamo un model basato su Entity Framework
creato con il nome di MyModel per cui ci ritroveremo, nel file
web.config, una sezione del genere:
<connectionStrings>
<add name="MyConnectionString"
connectionString="Server=mysrv\myinst;Database=mycatalog;Integrated Security=True" />
<add name="MyModel"
connectionString="metadata=res://*/MyModel.csdl|res://*/MyModel.ssdl|res://*/MyModel.msl;
provider=System.Data.SqlClient;
provider connection string=
"Data Source=mysrv\myinst;Initial Catalog=mycatalog;
Integrated Security=True;MultipleActiveResultSets=True""
providerName="System.Data.EntityClient" />
</connectionStrings>
Si può notare che le stringhe di connessione sono leggermente
diverse, dato che la stringa per il model richiede anche le
indicazioni degli schemi necessari alla mappatura dei dati.
Per raggiungere il nostro scopo, dovremo "estendere" la classe del
model, aggiungendo una classe in partial al model stesso, che si
chiamerà proprio MyModel.
public partial class MyModel
{
// ...
}
In questa classe creeremo una istanza singleton del model
stesso, utilizzando una proprietà statica:
// istanza statica privata da creare una sola volta
private static MyModel context = null;
// istanza statica pubblica da usare
public static MyModel Context
{
get
{
if (context == null)
{
context = CreateModelContext("MyConnectionString", "MyModel");
}
return context;
}
}
Come si può notare, la proprietà restituisce l'istanza privata,
preoccupandosi di inizializzarla se questa è ancora null (quindi se
siamo di fatto nel primo utilizzo della proprietà stessa).
L'inizializzazione viene fatta tramite un metodo a cui vengono
indicati il nome della connessione e il nome della classe del
model:
/// <summary>
/// Restituisce una istanza del model a partire da una connessione esistente nel file di config
/// </summary>
/// <param name="ConnStringName">Il nome della stringa di connessione</param>
/// <param name="ModelName">Il nome della classe del model</param>
/// <returns>Ritorna una istanza del model</returns>
private static MyModel CreateModelContext(string ConnStringName, string ModelName)
{
// recupero dal file di config la connection string già esistente
ConnectionStringSettings sqlconn = ConfigurationManager.ConnectionStrings[ConnStringName];
// inizializzo una istanza di EntityConnectionStringBuilder che ci consentirà di creare la
// connection per il model, e in questa valorizzo la proprietà "ProviderConnectionString" con
// la connection string appena recuperata
EntityConnectionStringBuilder ef = new EntityConnectionStringBuilder();
ef.Provider = "System.Data.SqlClient";
ef.ProviderConnectionString = sqlconn.ConnectionString;
ef.Metadata = string.Format(@"res://*/{0}.csdl|res://*/{0}.ssdl|res://*/{0}.msl", ModelName);
// ritorno l'istanza del model creata
return new MyModel(ef.ToString());
}