Sirve para MSSSQL también o cualquiera que use esquemas…
Estoy trabajando en un proyecto en el que quiero usar Entities Framework y me encontré con que no puedo, al menos no de una manera transparente, cambiar el esquema al que apuntan las tablas en tiempo de ejecución, esto queda más claro al ver el diseño de mi base de datos, es algo así:
EsquemaCliente1
----Tabla1
----Tabla2
----Tabla3
----Etc.
EsquemaCliente2
----Tabla1
----Tabla2
----Tabla3
----Etc.
Y así, esto es: para cada “cliente” tengo un esquema en el que se repiten las tablas, originalmente yo resolvía esto de manera relativamente simple desde que Npgsql añadió el parámetro “searchpath”, en base al usuario que se conectaba yo generaba un searchpath dinámicamente y asunto resuelto, bien… hasta que me decidí a usar EF, no vienen al caso las razones por las que lo hice solo decir que no me arrepiento y que la velocidad de desarrollo y la legibilidad del código han sigo algunas de ellas…
Bueno, a lo que vinimos: En EF no hay una manera nativa de hacer esto, no en esta versión al menos, el equipo de desarrollo ha recibido numerosos pedidos con respecto a esto y suponemos que en futuras versiones se podrá. Por ahora una solución es la siguiente, crear un método estático que nos devuelva el contexto con el esquema modificado, algo como lo siguiente:
public static ModeloDatos.ModeloDatosContext ObtenerContexto( string esquema )
{
var conn = ConfigurationManager.ConnectionStrings[ "ModeloDatosContext" ].ConnectionString;
var contexto = new ModeloDatos.ModeloDatosContext( conn.Replace( "cambiar", esquema ) );
var sReaders = new[] { XmlReader.Create( Assembly.Load( "Datos" ).GetManifestResourceStream( "ModeloDatos.ssdl" ) ) };
var mReaders = new[] { XmlReader.Create( Assembly.Load( "Datos" ).GetManifestResourceStream( "ModeloDatos.msl" ) ) };
var sCollection = new StoreItemCollection( sReaders );
var cCollection = contexto.MetadataWorkspace.GetItemCollection( DataSpace.CSpace ) as EdmItemCollection;
var csCollection = new StorageMappingItemCollection( cCollection, sCollection, mReaders );
contexto.MetadataWorkspace.RegisterItemCollection( sCollection );
contexto.MetadataWorkspace.RegisterItemCollection( csCollection );
var container = contexto.MetadataWorkspace.GetItem<EntityContainer>( "ModeloDatosstoreContainer", DataSpace.SSpace );
foreach ( var set in container.BaseEntitySets )
{
var esquemaActual = typeof( EntitySetBase ).GetField( "_schema", BindingFlags.NonPublic | BindingFlags.Instance ).GetValue( set );
if ( !string.IsNullOrEmpty( ( string ) esquemaActual ) && esquemaActual.ToString() == "cambiar" )
{
typeof( EntitySetBase ).GetField( "_schema", BindingFlags.NonPublic | BindingFlags.Instance ).SetValue( set, esquema );
}
}
return contexto;
}
Aquí lo que hacemos es pasarle al método el esquema al cual queremos acceder y nos devuelve una referencia al contexto con ese esquema como predeterminado, observen que yo he nombrado al esquema en los metadatos “cambiar” ya que en la base hay otros esquemas que son comunes a todos los clientes, como el de funciones, yo tengo, en este caso, todas las funciones en un mismo esquema y son compartidas por los esquemas de los clientes, en la cadena de conexión también lo cambiamos, esto lo hacemos para evitar que quede en el caché, simplemente ponemos algo así: searchpath=funciones,esquemacompartido1,esquemacompartido2,cambiar; y esto hará el truco :)
Este método está basado en algo que encontré en este blog: http://blogs.microsoft.co.il/blogs/idof/archive/2008/08/22/change-entity-framework-storage-db-schema-in-runtime.aspx
Espero que les sea útil ya que yo estuve un par de días volviéndome loco tratando de conseguir esto ;)
P.D.: Hay otra manera, lo mismo que, supongo, pensamos todos, cambiar directamente el ssdl, por alguna razón esto no funciona, no al menos como se espera que lo haga, aquí les dejo una dirección donde investigar un poco.
Hasta la próxima
Jerónimo Milea
No hay comentarios:
Publicar un comentario