Il comportamento di default del wizard dell’EF accorpa i metadati del modello come risorse del nostro assembly e inserisce una stringa di connessione nell’ app.config o nel web.config in modo da referenziare a runtime tali risorse:
<connectionStrings>
<add name="NorthwindEntities"
connectionString="metadata=res://*/NorthwindModel.csdl|res://*/NorthwindModel.ssdl|res://*/NorthwindModel.msl;..."
providerName="System.Data.EntityClient" />
</connectionStrings>
Tuttavia, “embeddare” i metadati del nostro modello come risorsa dell’assembly può costituire un limite: infatti sorgerebbero dei problemi qualora volessimo
- esporre i metadati alla modifica di agenti esterni
- referenziare tramite connection string dei metadati definiti altrove sul file system
- caricare i metadati on-demand magari leggendoli da stream di rete
Infatti, esistono dei casi in cui può essere utile distinguere tra metadati di test e metadati di produzione o comunque prevedere delle politiche che possano richiedere storage model (SSDL) e mapping model (MSL) diversi, pur mantenendo l’integrità del modello concettuale (CSDL) utilizzato dallo sviluppatore.
Una prassi molto comune è impostare l’opzione 'Metadata Artifact Processing' del designer a 'Copy to Output Directory'.
In questo modo nella bin del nostro progetto troviamo i metadati SSDL, MSL e CSDL separati fisicamente dalla .dll di output.
Quindi abbiamo già raggiunto l’obiettivo di poter modificare i metadati (solitamente SSDL e MSL) senza dover ricompilare la nostra applicazione. A questo punto possiamo scegliere di modificare la nostra connection string in modo che punti al corretto insieme di file:
string connectionString = @"metadata=.\NorthwindModel.csdl|.\NorthwindModel.ssdl|.\NorthwindModel.msl;
provider=System.Data.SqlClient; provider connection string=""..."" ";
using (NorthwindContext context = new NorthwindContext(connectionString)) { ... }
Uno step ulteriore che si può prevedere è il caricamento dinamico di metadati non soltanto da una locazione fisica su file system, ma anche da un generico stream (es. da un web server via HTTP). A riguardo, il seguente esempio mostra come caricare dinamicamente CSDL, SSDL e MSL in modo da creare un oggetto di tipo EntityConnection da passare al nostro ObjectContext:
// Get CSDL/SSDL/MSL from a generic stream ...
string csdl = "<?xml version="1.0" encoding="utf-8"?><Schema...</Schema>";
string ssdl = "<?xml version="1.0" encoding="utf-8"?><Schema...</Schema>";
string msl = "<?xml version="1.0" encoding="utf-8"?><Mapping...</Mapping>";
XmlTextReader csdlXmlReader = new XmlTextReader(new StringReader(csdl));
XmlTextReader ssdlXmlReader = new XmlTextReader(new StringReader(ssdl));
XmlTextReader mslXmlReader = new XmlTextReader(new StringReader(msl));
EdmItemCollection edmItemCollection = new EdmItemCollection(new[] { csdlXmlReader });
StoreItemCollection storeItemCollection = new StoreItemCollection(new[] { ssdlXmlReader });
StorageMappingItemCollection storageMappingItemCollection = new StorageMappingItemCollection(edmItemCollection, storeItemCollection, new[] { mslXmlReader });
// Create the metadata workspace for the EntityConnection ...
MetadataWorkspace metadataWorkspace = new MetadataWorkspace();
metadataWorkspace.RegisterItemCollection(edmItemCollection);
metadataWorkspace.RegisterItemCollection(storeItemCollection);
metadataWorkspace.RegisterItemCollection(storageMappingItemCollection);
string sqlConnectionString = @"Data Source=.\SQLSRV08;Initial Catalog=Northwind;User ID=XXX;Password=XXX;";
EntityConnection entityConnection = new EntityConnection(metadataWorkspace,new SqlConnection(sqlConnectionString));
using (NorthwindContext context = new NorthwindContext(entityConnection)) { ... }