Asp.net 5.0 MVC6 EF6 Migration Scripts - powershell

I am working on Asp.net 5.0 mvc6 and I am wanting to use entityframework 6 because 7 isn't completely coded yet and I have been able to get it to do everything but migration.
When I type enable-migration, add-migration or update-datatabase I get
enable-migration : The term 'enable-migration' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of
the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:1
+ enable-migration
+ ~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (enable-migration:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
I'm pretty sure these commands are not in powershell. I did however find that there are tools in %userdir%.dnx\packages\EntityFramework\6.1.3\tools. Researching migrate.exe a little bit the little I did find they told me that it only works with proj files and so doesn't work with the new setup.
I have also tried to go the programming route with this code in the constructor of dbcontext I have:
var configuration = new MigrationConfiguration();
var migrator = new DbMigrator(configuration);
migrator.Configuration.TargetDatabase = new DbConnectionInfo(nameOrConnectionString, "System.Data.SqlClient");
if (migrator.GetPendingMigrations())
{
migrator.Update();
}
and this code in my confirmation script:
public MigrationConfiguration()
{
AutomaticMigrationsEnabled = true;
MigrationsAssembly = Assembly.GetAssembly(typeof(InitialCreate));
MigrationsNamespace = "[Namespace of my migration scripts]";
}
Before I made any of this the database made a __migrationHistory table with an 201509291902537_InitialCreate in it, so I made one file with that name and made another called 201509291902538_test they both look like this:
201509291902537_InitialCreate:
namespace Infrastructure.EF.Migrations
{
using System.Data.Entity.Migrations;
public partial class InitialCreate : DbMigration
{
public override void Up()
{
}
}
}
201509291902538_test:
namespace Infrastructure.EF.Migrations
{
using System;
using System.Data.Entity.Migrations;
public partial class test: DbMigration
{
public override void Up()
{
Sql("insert into LegalEntity (Id, Name ) values(" + Guid.NewGuid() + ", 'Test'");
}
}
}
No matter what I tried migrator.GetPendingMigrations() never says it has any new updates and if I made a fake update and tell it exactly what it needs to update it still doesn't work it just throws a null reference exception on the update function.
Here's my fake migrator:
namespace Infrastructure.EF.Contexts
{
public class Migrator : DbMigrator
{
public Migrator(DbMigrationsConfiguration configuration) : base(configuration)
{
}
public override IEnumerable<string> GetDatabaseMigrations()
{
return new List<string>() { "InitialCreate" };
}
public override IEnumerable<string> GetLocalMigrations()
{
return new List<string>() { "InitialCreate", "test" };
}
public override IEnumerable<string> GetPendingMigrations()
{
return new List<string>() { "test" };
}
}
}
project.json:
{
"version": "1.0.0-*",
"dependencies": {
"Autofac.Framework.DependencyInjection": "4.0.0-beta5-*",
"AutoMapper": "4.0.4",
"EntityFramework": "6.1.3",
"log4net": "2.0.3",
"Microsoft.AspNet.Http.Abstractions": "1.0.0-beta5",
"Microsoft.CSharp": "4.0.0-*",
"Microsoft.Framework.Configuration.Json": "1.0.0-beta5",
"RestSharp": "105.2.3",
"System.Linq": "4.0.0-*",
"System.Runtime": "4.0.10-*",
"System.Threading": "4.0.10-*"
},
"frameworks": {
"dnx451": {
}
},
"configurations": {
"DV": { },
"QA": { },
"TR": { },
"PR": { }
}
}
I have tried it with both the class name and the file name and neither seems to work.
Has anybody had any luck with any of these things or see what I'm doing wrong with one of them?

If you want to use EF6 with ASP.NET MVC6, then expose EF6 repositories as Web API 2 in .NET 4.5 and consume them in ASP.NET MVC6.
I know its lots of additional work, I followed this approach to learn and develop MVC6 applications because of existing EF6 data access layer and similar issues in EF6 to EF7 migrations.

Have you tried this: http://www.bricelam.net/2014/09/14/migrations-on-k.html ?
It's for EF 7, but I think you could just change the version to EF6.

Related

Entityframework Core 2.0 Migration will get executed when application runs first time?

I would like to know whether the EF migrations will executed along with seed data without running update-database command? ie. without executing update-database command, i can see all tables created in the database.
Is there any problem or is this the expected behaviour?
I am using separate method to seed data:
public async Task SeedAsync(IServiceProvider serviceProvider)
{
//Based on EF team's example at https://github.com/aspnet/MusicStore/blob/dev/samples/MusicStore/Models/SampleData.cs
using (var serviceScope = serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope())
{
var dbContext = serviceScope.ServiceProvider.GetService<WorkflowDBContext>();
if(!dbContext.AllMigrationsApplied())
{
serviceScope.ServiceProvider.GetService<WorkflowDBContext>().Database.Migrate();
if (!await dbContext.Alert.AnyAsync())
{
await SeedData(dbContext);
}
}
}
}
public static class DbContextExtension
{
public static bool AllMigrationsApplied(this WorkflowDBContext context)
{
var applied = context.GetService<IHistoryRepository>()
.GetAppliedMigrations()
.Select(m => m.MigrationId);
var total = context.GetService<IMigrationsAssembly>()
.Migrations
.Select(m => m.Key);
return !total.Except(applied).Any();
}
}
Thanks
EF Core won't ever automatically apply migrations. Your application may be calling DbContext.Database.EnsureCreated() or Migrate() somewhere...

EntityFramework Core automatic migrations

Is there any code to perform automatic migration in Entity Framework core code first in asp.net core project?
I do it simply in MVC4/5 by adding
Database.SetInitializer(new MigrateDatabaseToLatestVersion<AppDbContext, MyProject.Migrations.Configuration>());
public Configuration() {
AutomaticMigrationsEnabled = true;
}
This saves time when entities changed
You can call context.Database.Migrate()in your Startup.cs
eg:
using (var context = new MyContext(...))
{
context.Database.Migrate();
}
EF core doesn't support automatic migrations.So you have to do it manually.
From the perspective of automatic migrations as a feature, we are not
planning to implement it in EF Core as experience has showed code-base
migrations to be a more manageable approach.
You can read full story here : Not to implement Automatic Migrations
This is the way they do it in IdentityServer4 http://identityserver.io
public void ConfigureServices(IServiceCollection services)
{
var connectionString = Configuration.GetConnectionString("DefaultConnection");
var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
// Add framework services.
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
...
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
// this will do the initial DB population
InitializeDatabase(app);
}
private void InitializeDatabase(IApplicationBuilder app)
{
using (var scope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
{
scope.ServiceProvider.GetRequiredService<ApplicationDbContext>().Database.Migrate();
scope.ServiceProvider.GetRequiredService<PersistedGrantDbContext>().Database.Migrate();
...
}
}
Automatic migrations is not supported in EF Core. Migration it is necessary to create hands. To automatically apply all existing handmade migrations need to add the following code in the class Program:
public class Program
{
public static void Main(string[] args)
{
var host = CreateWebHostBuilder(args).Build();
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
var context = services.GetRequiredService<MyDbContext>();
context.Database.Migrate(); // apply all migrations
SeedData.Initialize(services); // Insert default data
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred seeding the DB.");
}
}
host.Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
}
Following Microsoft's documentation
https://learn.microsoft.com/en-us/aspnet/core/data/ef-mvc/intro
If you are using dependency injection, first, you need to setup a static class Data/DbInitializer.cs and add the following code:
public static class DbInitializer
{
public static void Initialize(ApplicationDbContext context)
{
context.Database.Migrate();
// Add Seed Data...
}
}
Notice, this is also where you can add seed data.
Next, in your Program.cs file, add the following code
public static void Main(string[] args)
{
var host = BuildWebHost(args);
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
var environment = services.GetRequiredService<IHostingEnvironment>();
if (!environment.IsDevelopment())
{
var context = services.GetRequiredService<ApplicationDbContext>();
DbInitializer.Initialize(context);
}
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred while seeding the database.");
}
}
host.Run();
}
In my case, I'm checking the environment to make sure I'm in development so I can control the migrations/updates. However, in production, I want them to be automatic for continuous integration. As others have mentioned, this is probably not best practices but on small projects it works great.
My working automigration code Asp Net Core 2.0.7.
// startup.cs
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
// configure app
SeedData.Initialize(app.ApplicationServices);
}
// dbInitializer.cs
public static class SeedData
{
public static void Initialize(IServiceProvider serviceProvider)
{
using (var serviceScope = serviceProvider.CreateScope())
{
var context = serviceScope.ServiceProvider.GetService<ApplicationDbContext>();
// auto migration
context.Database.Migrate();
// Seed the database.
InitializeUserAndRoles(context);
}
}
private static void InitializeUserAndRoles(ApplicationDbContext context)
{
// init user and roles
}
}
You can call Database.Migrate() in db context constructor.
If the model changes a lot and you manage a medium - large team, migrations leads more problems than solution at least in development phase.
I published a nuget package with automatic migration for .net core, EFCore.AutomaticMigrations - https://www.nuget.org/packages/EFCore.AutomaticMigrations/, so manual migration not needed anymore.
You can call directly in Program class, like bellow:
public static void Main(string[] args)
{
var host = CreateWebHostBuilder(args);
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
var loggerFactory = services.GetRequiredService<ILoggerFactory>();
var logger = loggerFactory.CreateLogger<Program>();
try
{
var environment = services.GetRequiredService<IWebHostEnvironment>();
if (environment.IsDevelopment())
{
var context = services.GetRequiredService<ApplicationContext>();
MigrateDatabaseToLatestVersion.ExecuteAsync(context).Wait();
}
}
catch (Exception ex)
{
logger.LogError(ex, "An error occurred creating/updating the DB.");
}
}
host.Run();
}
Frank Odoom's answer works even 4 years later in .net 5, but it is not the intended context to call the migration at runtime... And, it appears it never was because it requires us to mock the DbContext with DbContextOptions whos documentation explicitly states:
"The options to be used by a DbContext. You normally override OnConfiguring(DbContextOptionsBuilder) or use a DbContextOptionsBuilder to create instances of this class and it is not designed to be directly constructed in your application code."
Here is my suggestion:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
// database provider is configured before runtime migration update is applied e.g:
optionsBuilder.UseSqlServer(ConnectionString);
Database.Migrate();
}
Edit:
My suggestion is actually horrible if you are using multiple DBContexts in the same project... It would migrate the database multiple times. Which would most likely not break anything, but it would slow startup considerably.
my best advice is not to use the automatic migration.It is always better to add migrations manually and also avoid bulk migration and stick to best practice for using manual migration
automatic migration is not a magic tool and there will be several occasions where you might want to add some addition changes to the migration. You only accomplish by using manual migration.
To enable migration, type "enable-migrations" in the package manager console
This way you will have full control of upgrading or downgrading your database and also easy to track migrations.
Just three simple steps in package manager console.
1) add-migrations [some name for your migration]
2) migrations is generated for the changes, you review them and also can
make changes to it
3) update-database your migration is complete now.
handling migration is less painful!

Using WebClient in ASP.NET 5

I am working in the VS15 beta and trying to use WebClient. While System.Net is referenced, and the intellisense suggests the WebClient class is available, on build I get the following error:
The type or namespace name 'WebClient' does not exist in the namespace 'System.Net' (are you missing an assembly reference?) MyProj.ASP.NET Core 5.0 HomeController.cs
I am doing the following simplistic code:
var client = new System.Net.
var html = client.DownloadString(url);
When I go to the definition of Web Client, it shows me the source. Not quite sure what the issue is - is WebClient moved? I am struggling to find the resolution.
Thanks!
Not sure about WebClient, but you can use System.Net.Http.HttpClient to make web requests as well.
Add these references to the project.json:
"frameworks": {
"aspnet50": {
"frameworkAssemblies": {
"System.Net.Http": "4.0.0.0"
}
},
"aspnetcore50": {
"dependencies": {
"System.Net.Http": "4.0.0-beta-*"
}
}
},
And then here's how to call it from an MVC 6 action method:
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Microsoft.AspNet.Mvc;
namespace WebApplication50.Controllers
{
public class HomeController : Controller
{
public async Task<IActionResult> Index()
{
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("MyClient", "1.0"));
var result = await httpClient.GetStringAsync("http://www.microsoft.com");
...
return View();
}
}
}
You can still use WebClient if you only target full .NET Framework instead of .NET Core by in your project.json changing:
"frameworks": {
"dnx451": { },
"dnxcore50": { }
},
to
"frameworks": {
"dnx451": { }
},

Entity framework code first migration to multiple database

Lets say we have the architecture model of web application where we have 1 database per 1 account. Database structure is the same for these accounts and differs only on data with in. How can i configurate a migrations in code first model.
Now I have next solution.
In the main method or in global.asax something like this:
var migration_config = new Configuration();
migration_config.TargetDatabase = new DbConnectionInfo("BlogContext");
var migrator = new DbMigrator(migration_config);
migrator.Update();
migration_config.TargetDatabase = new DbConnectionInfo("BlogContextCopy");
migrator = new DbMigrator(migration_config);
migrator.Update();
Connection strings for example in app_config file:
<connectionStrings>
<add name="BlogContext" providerName="System.Data.SqlClient" connectionString="Server=(localdb)\v11.0;Database=MigrationsDemo.BlogContext;Integrated Security=True;"/>
<add name="BlogContextCopy" providerName="System.Data.SqlClient" connectionString="Server=(localdb)\v11.0;Database=MigrationsDemo.BlogContextCopy;Integrated Security=True;"/>
</connectionStrings>
Configuration class and context:
internal sealed class Configuration : DbMigrationsConfiguration<MigrationsDemo.BlogContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = true;
AutomaticMigrationDataLossAllowed = true;
}
protected override void Seed(MigrationsDemo.BlogContext context) {
}
}
public class BlogContext : DbContext {
public BlogContext() {}
public BlogContext(string connection_name) : base(connection_name) {
}
public DbSet<Blog> Blogs { get; set; }
}
In addition to your excellent answer, you can use an external config file (i.e. "clients.json") instead of hardcoding them, put all the database infos in key-value pairs into the json file and load it during startup.
Then, by iterating over the key-value pairs, you can do the initialization.
The clients.json:
{
"DatabaseA": "DatabaseAConnectionString",
"DatabaseB": "DatabaseBConnectionString",
"DatabaseC": "DatabaseCConnectionString",
...
}
Provide a method to handle the migrations:
public static void MigrateDatabases(IDictionary<string,string> databaseConfigs)
{
foreach (var db in databaseConfigs)
{
var config = new Configuration
{
TargetDatabase = new DbConnectionInfo(db.Value, "System.Data.SqlClient")
};
var migrator = new DbMigrator(config);
migrator.Update();
}
}
Then during startup, (I use OWIN, so it's in my Startup.cs, could also be global.asax.cs):
string json;
var path = HttpRuntime.AppDomainAppPath;
using (var reader = new StreamReader(path + #"Config\clients.json"))
{
json = reader.ReadToEnd();
}
var databases = JsonConvert.DeserializeObject<IDictionary<string, string>>(json);
MigrateDatabases(databases);
Works like a charm for me :)
See the page on automatic migrations during application startup.
If you use this method to apply your migrations, you can use any connection string (or whatever method you have to identify exactly which database to connect to) and upon connection, the migration will be performed.

A little baffled on DBMigrations with Code First and EF

I have a project that I created and enabled Migrations on. It created it with 4.3 so I think it is the latest. I have some code in the constructor of the context that executes the update (see code below) and that seems to work everytime I add something like a nullable string column or do something that does not change the database in non consistent manner. My scenario is I change my model, and when I watch sql trace, it does the alter columns for me automatically.
My question is I want to do the "up" and "down" methods but am confused on when they run. That is say I'm on version 1 now, I put some code in my "up" method to add a column, then later when I want to go to version 3, how does it know which "up" method to call?
Confused. -Peter
namespace MigrationsAutomaticDemo.Migrations
{
using System.Data.Entity.Migrations;
public partial class AddBlogRating : DbMigration
{
public override void Up()
{
AddColumn("Blogs", "Rating", c => c.Int(nullable: false, defaultValue: 3));
}
public override void Down()
{
DropColumn("Blogs", "Rating");
}
}
}
,
public SiteDB()
{
UpdateDatabase();
}
// http://joshmouch.wordpress.com/2012/04/22/entity-framework-code-first-migrations-executing-migrations-using-code-not-powershell-commands/
public static int IsMigrating = 0;
private static void UpdateDatabase()
{
if (0 == Interlocked.Exchange(ref IsMigrating, 1))
{
// Manually creating configuration:
var migratorConfig = new DbMigrationsConfiguration<SiteDB>();
migratorConfig.AutomaticMigrationsEnabled = true;
// Using configuration defined in project:
//var migratorConfig = new DbMigrationsConfiguration();
// 3
//var dbMigrator = new DbMigrator(new Settings());
var dbMigrator = new DbMigrator(migratorConfig);
dbMigrator.Update();
Interlocked.Exchange(ref IsMigrating, 0);
}
}
If you enable the automatic migration in the migration configuration, then you don't need to specify the target migration. The migrator will automatically scaffold the changes based on the snapshot of current context and target database.
var migratorConfig = new DbMigrationsConfiguration<SiteDB>();
migratorConfig.AutomaticMigrationsEnabled = true;
In your case, you want to upgrade your database by using specific migration. All you need to do is mentioning explicitly which migration to upgrade.
Configuration configuration = new Configuration();
DbMigrator migrator = new DbMigrator(configuration);
migrator.Update("201204250656061_AddBlogRatingVersion2");
migrator.Update("201204250656061_AddBlogRatingVersion3");
migrator.Update("201204250656061_AddBlogRatingVersionX");