2011-12-30 17 views
31

Estoy trabajando en un proyecto que puede terminar con múltiples versiones/variantes de UI, pero hasta ahora tengo dos subproyectos en mi solución Web que contiene una interfaz web con ASP.NET MVC . Proyecto de servicio es el lugar donde tengo definido el contexto y los modelos de mi base de datos.Lugar para poner Database.SetInitializer

Mi objetivo es tener un mínimo o posiblemente ninguna referencia al código específico de EF en mi proyecto web. Quiero que sea independiente, así que cuando cambio los dlls con backend de servicio (desde digamos SQL a XML o MySQL) no debería hacer modificaciones múltiples en mi proyecto MVC.

Esto es como se ve:

Project layout

Mis preguntas son: - hasta ahora he encontrado ningún ejemplo de la utilización de Database.SetInitializer en otro lugar que Global.asax. Me gustaría volver a crear la base de datos si el modelo ha cambiado en mi clase de DatabaseContextProvider, similar a la de fábrica, o en la clase de servicio que extrae datos del contexto y los proporciona a la IU con DTO. ¿Hay algún inconveniente de esa ubicación? - Me gustaría que el connectionString del contexto fuera configurable con el archivo Properties/Settings.settings. ¿Es razonable?

Respuesta

14

Necesitará un mecanismo para llamar al método Database.SetInitializer antes del primer uso del DbContext. Es por eso que generalmente se llama en el archivo Global.asax.

Puede crear una clase con un método de inicialización en su proyecto tm.Service y llamarlo en el método Application_Start y poner el Database.SetInitializer en ese método de inicialización.

Está bien proporcionar la cadena de conexión de un archivo de configuración.

8

Lo puse en el constructor de DbContext y funciona para mí.

public myDbContext() : base(connectionToDatabase) { 
     Database.SetInitializer<myDbContext>(null); 
    } 

La solución anterior funcionará, pero no es tan eficiente como el siguiente código:

protected void Application_Start() 
    { 
     Database.SetInitializer<myDbContext>(null); 
    } 

En mi caso no tengo una referencia de mi DAL en la interfaz de usuario y para eso Por lo que hice fue crear una configuración de EntityFramework y registrar mi configuración usando el reflejo.

protected void Application_Start() 
    {   
     EntityFrameworkConfig.RegisterSettings(); 
    } 


public static class EntityFrameworkConfig 
{ 
    public static void RegisterSettings() 
    { 
     // Use the file name to load the assembly into the current 
     // application domain. 
     Assembly a = Assembly.Load("MyAssembly"); 
     // Get the type to use. 
     Type myType = a.GetType("MyType"); 
     // Get the method to call. 
     MethodInfo myMethod = myType.GetMethod("MySettingsMethod"); 
     // Create an instance. 
     object obj = Activator.CreateInstance(MyType); 
     // Execute the method. 
     myMethod.Invoke(obj, null); 
    } 
} 

    public void Configurations() 
    { 
     //Other settings 
     Database.SetInitializer<myDbContext>(null); 
    } 

Actualizado

Con Entity Framework 6, ahora se puede utilizar el NullDatabaseInitializer

Database.SetInitializer(new NullDatabaseInitializer<MyDbContext>()); 
+6

Un posible problema al hacer esto es que podría llamarse cada vez que se construye la clase myDbContext, lo que podría ser muy bien cada vez que utilice la base de datos. Me imagino que esta es una operación razonablemente costosa y no quieres que esto suceda. Usar Global.asax Application_Start o un constructor estático en la clase DataContext garantiza que el código solo se invoque una vez, cuando se inicia la aplicación. – Holf

+0

Estoy de acuerdo con Holf, el código debería estar en la application_start –

32

Para evitar el acoplamiento, preferiría no establecer el inicializador fuera de la Asamblea que tengan el DataContext. Entonces, agregué un constructor estático para el DataContext. De esta forma, cada proyecto que haga referencia a esta Asamblea disfrutará del inicializador sin establecerlo explícitamente, y el inicializador se establece solo una vez por proceso.

static MyDataContext() 
{ 
    Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyDataContext, Configuration>()); 
} 

La cadena de conexión se tomará desde el archivo de configuración de la aplicación.

+9

No estoy seguro de que sea una buena idea, porque entonces tiene un acoplamiento ajustado entre 'DbContext' y el inicializador. La política de inicialización depende del contexto, p. para las pruebas se usaría un 'DropCreateDatabaseAlways' y para la producción un' CreateDatabaseIfNotExists' ... – Pragmateek

3

Microsoft hizo posible, para EF6 en adelante, configurar un inicializador por contexto de base de datos en el archivo de configuración de la aplicación. Consulte la última sección en esta página de Microsoft: https://msdn.microsoft.com/en-us/data/jj556606.aspx

Esto, al igual que el enfoque "Global.asax", tiene la ventaja de que, p. los proyectos de prueba unitaria pueden usar un inicializador diferente para el mismo contexto de base de datos.

+0

Creo que es un inicializador por contexto, no por base de datos. Múltiples contextos pueden operar en el mismo DB. –

+0

@DanielMackay ¡Pero yo escribí el "contexto de la base de datos"! ¿Por casualidad pasaste por alto la palabra "contexto" debido a la línea que se encuentra justo después de la palabra "base de datos"? –

+1

no recomiendan la configuración, más bien dicen que puedes hacer eso, y también lo hacen en el código. Para ellos, ahora puedes hacerlo de cualquier manera. –

Cuestiones relacionadas