Estrategia de inicialización personalizada para el código EF primero que no suelta las tablas para agregar una columna
-
24-10-2019 - |
Pregunta
El último paquete NUGET de Código EF First viene con una implementación personalizada de IDatabaseInitializer
llamó DontDropDbJustCreateTablesIfModelChanged
. Como su nombre lo indica, cuando se detecta un cambio de modelo, no dejará caer y recreará toda la base de datos, simplemente soltará y recreará las tablas.
Digamos que tengo esta clase de modelo:
public class User
{
public string Username { get; set; }
// This property is new; the model has changed!
public string OpenID { get; set; }
}
¿Cómo se haría para implementar un IDatabaseInitializer
que tampoco deja caer ninguna mesa. En este caso, solo agregaría un OpenID
columna a la tabla de usuario?
Solución
Creo que es una cuestión de SQL. Entonces, para SQL Server, puede escribir algo como:
public class MyInitializer : IDatabaseInitializer<MyContext>
{
public void InitializeDatabase(MyContext context)
{
context.Database.SqlCommand(
@"
IF NOT EXISTS (SELECT 1 FROM sys.columns AS col
INNER JOIN sys.tables AS tab ON tab.object_Id = col.object_Id
WHERE tab.Name = 'User' AND col.Name = 'OpenId')
BEGIN
ALTER TABLE dbo.User ADD OpenId INT;
END");
}
}
Pero de la misma manera, puede ejecutar dicho script sin agregarlo a su aplicación, lo que creo que es un enfoque mucho mejor.
Otros consejos
Con la versión actual del código primero, no puede simplemente modificar su esquema y preservar los datos que pueda tener en sus tablas. Si se mantiene los datos, como las tablas de datos / búsqueda de referencia, es importante con esta versión, puede crear su propio inicializador y anular el método de semilla para llenar sus tablas
public class MyDbInitializer : DropCreateDatabaseIfModelChanges<MyContext>
{
protected override void Seed(MyContext context)
{
var countries = new List<Country>
{
new Country {Id=1, Name="United Kingdom"},
new Country{Id=2, Name="Ireland"}
};
countries.ForEach(c => context.Countries.Add(c));
}
}
Y luego use esto en su aplicación_start:
Database.SetInitializer<MyContext>(new MyDbInitializer());
Creo que el equipo EF está abordando actualmente, pero no estaba listo para su lanzamiento en el momento en que salió la primera caída del código. Puede ver una vista previa aquí: Código Primeras migraciones