Cadenas de Conexion en Entity Framework

En los últimos meses hemos desarrollado en 3Metas varios proyectos utilizando el Entity Framework como modelo de acceso a datos, especialmente me gusta el modelo Code First en los que teóricamente me desentiendo del motor de base de datos y me enfoco en el modelo de objetos, no siempre es tan fluido y a hay que desempolvar el manual de Linq para que tatuárselo en un brazo, pero en general la experiencia ha sido muy buena.

Ahora bien, una de las cosas más interesante del Entity Framework cuando se trabaja con Code First consiste en la capacidad de crear bases de datos que reflejan el modelo y sobre las que se van a almacenar los datos y esto es casi mágico para el desarrollador, pero ya en el ambiente de producción y en aplicaciones corporativas se requiere más control, así que es mejor definir su propia cadena de conexión. Esto resulta un poco complicado la primera vez porque uno siempre se esta preguntando pero como supo EF a donde conectarse, servidor, usuario, nombre de la base de datos, etc.  Revisando la documentación del entity framewor en el objeto DbContext que es de donde se hereda el controlador de la base de datos vemos lo siguiente en el constructor

Constructs a new context instance using conventions to create the name of the database to which a connection will be made. The by-convention name is the full name (namespace + class name) of the derived context class.  See the class remarks for how this is used to create a connection.

y un poco más en la documentación de clase se encuentra lo siguiente:

The Entity Data Model backing the context can be specified in several ways. When using the Code First approach, the System.Data.Entity.DbSet<TEntity> properties on the derived context are used to build a model by convention.   The connection to the database (including the name of the database) can be specified in several ways.  If the parameterless DbContext constructor is called from a derived context, then the name of the derived context is used to find a connection string in the app.config or web.config file. If no connection string is found, then the name is passed to the DefaultConnectionFactory registered on the System.Data.Entity.Database class.

The connection factory then uses the context name as the database name in a default connection string. (This default connection string points to .SQLEXPRESS on the local machine unless a different DefaultConnectionFactory is registered.) Instead of using the derived context name, the connection/database name can also be specified explicitly by passing the name to one of the DbContext constructors that takes a string. The name can also be passed in the form “name=myname”, in which case the name must be found in the config file or an exception will be thrown.

Note that the connection found in the app.config or web.config file can be a normal database connection string (not a special Entity Framework connection string) in which case the DbContext will use Code First.

Que básicamente nos dice que la base de datos se llamara como se llame la clase (incluido el namespace) de donde que fue heredada de DBContext, por ejemplo, si mi clase se llama MyNamespace.MyComponente.MyClase, así se llamara la nueva base de datos en una instancia de SQL que se llame SQLExpress dentro de la maquina en la que esta ejecutándose la Dll. Ahora bien si se quiere definir el nombre de la base de datos se puede invocar el constructor de DBContext asi:

public MTRDB() : base(“MyDB”) { }

Donde MTRDB es el nombre de la clase que esta heredando de DBContext y MyDB es el nombre con el que quiero que se cree la base de datos en la instancia SQLExpress de la maquina local.

Ahora si lo que se quiere es prevenir que EF vuelva a crear la base de datos o que utilice una base de datos existente en otro servidor, con otro nombre, con seguridad de SQL o cualquier combinación de las anteriores se debe crear una llave de tipo Connectionstring en el archivo config (web.config o app.config) de la solución que esta referenciando la clase que heredo de DBContext, esta llave debe tener el mismo nombre de la clase (si no se uso el constructor) o el mismo nombre que se uso en el constructor, por ejemplo y de acuerdo al ejemplo anterior, si la app encuentra una llave de configuración que se llame MyDB utilizará la información de esa cadena de conexión para conectarse a la BD donde espera encontrar los modelos de objetos.

Un detalle importante es que cuando se utilizan cadenas de conexión es bueno incluir el parámetro  MultipleActiveResultSets=True en la cadena de conexión, ya que de no hacerlo el DBContext solo podrá manejar un resultado al tiempo y no permitirá ejecutar otros comandos mientras no se cierre el proceso del anterior. así que algo como esto


using (WFEngineDb wfEngineDb = new WFEngineDb())
{
var fullfilledTransitions = wfEngineDb.Database.SqlQuery<FullfiledTransition>(sb.ToString(), activityInstanceId);
foreach (var fullfilledTransition in fullfilledTransitions)
{
if ((fullfilledTransition.Requested - fullfilledTransition.Fullfilled) == 0)
{
var transition = wfEngineDb.transitions.Find(fullfilledTransition.Transition_id);
transitions.Add(transition);
}
}
}

Generaría un error ya que el find no puede ejecutarse dentro de la operación de consulta a la base de datos. El error seria algo del tipo: There is already an open DataReader associated with this Command which must be closed first.

 La capacidad del EF de distiguir por configuración si estoy en desarrollo o en producción por la presencia o no de la cadena de conexión en el archivo config de la solución nos ha parecido no solo muy útil sino que se ha vuelto parte de nuestro proceso de desarrollo permitiéndonos probar el componente contra múltiples ambientes de una forma muy fácil y rápida.

En uno de nuestros proyectos, por ejemplo,  teníamos una base de datos en producción con más de 70 millones de registros y soportando un web site con picos de hasta un millón de visitantes diarios y el EF se comporto de maravilla (después de crear índices y hacer un tunning juicioso de la base de datos), así que creemos que es una tecnología bastante madura y robusta como para poner rápidamente aplicaciones importantes en producción.

Pd. No soy experto en nhibernate pero me gusta de EF Code First que no hay archivos de configuración ni nada aparte de mi clase para definir el modelo y cuando se necesita algo particular el Dataanotations hace el trabajo muy bien.