I am using Entity Framework to create and seed my database using Code First and the MigrateDatabaseToLatestVersion initializer. The issue I am having is when I launch the ASP.NET MVC app without a database create EF will create the database but will not seed on the first run through. If I kill iisexpress and relaunch the app after creating the database my seeds go in fine. I would expect my seeds to be ran after the database gets created but I don't even hit a break point in my seeds method on the first run through. I hit break points on the second run through without problems but it is annoying to have to run the app twice after killing the DB just to get my seeds to work.
Below is my Configuration class:
public sealed class Configuration : DbMigrationsConfiguration<CompassDb>
{
public Configuration()
{
AutomaticMigrationsEnabled = true;
AutomaticMigrationDataLossAllowed = true;
}
protected override void Seed(CompassDb context)
{
ModuleSeed.Seed(context);
PermissionGroupSeed.Seed(context);
var permissions = PermissionSeed.Seed(context);
var roles = RoleSeed.Seed(context, permissions);
UserSeed.Seed(context, roles, permissions);
OcmPluginSeed.Seed(context);
SCACSeed.Seed(context);
ModuleConfigurationSeed.Seed(context);
}
}
I am calling this in my Global.asax file.
Database.SetInitializer(new MigrateDatabaseToLatestVersion<CompassDb, Configuration>());
using (var db = new CompassDb())
{
db.Database.Initialize(true);
}
I did have a query to get a version number from the db on page load to create the database but calling the initializer directly seems a little cleaner. I was having the issue before when I was making a DB call through EF as well. I moved away from the DB call because I am only using EF for the automatic DB creating and migration then I switch to Dapper for any database communication.
I found this post here where people were having the same issue as me but it doesn't seem like it was ever resolved.
UPDATE
I found out that the issue is related to my migration files. I updated the primary keys of all my models from int to long and had to delete my current migration files. After deleting the files everything started working as normal, the database would be created and seeded on the same request. I then created my initial schema migration and am back at the same issue where the database does not seed until the 2nd time launching the site. I am using ELMAH in the project and have to update the first migration file to execute the sql file that is included when installing ELMAH via nuget. This could be related to the issue and I will do more testing to see if this is the cause.
I think I had the same or similar problem. Try to make a manual initializer. It's clean, simple and short. See this example:
Public Class CustomDbInit
Implements IDatabaseInitializer(Of MyContext)
Public Sub InitializeDatabase(context As MyContext) Implements System.Data.Entity.IDatabaseInitializer(Of MyContext).InitializeDatabase
If Not context.Database.Exists Then
context.Database.CreateIfNotExists()
' Some other processes, such as WebMatrix initialization if you're using SimpleMembership like I do
End If
End Sub
End Class
Then on the Global.asax Application_Start method, initialize it like this:
Dim context As New MyContext()
If Not context.Database.Exists Then
Database.SetInitializer(New CustomDbInit())
context.Database.Initialize(False)
End If
Related
I am developing a ASP.NET MVC web application using code first with entity framework.
The problem I am facing is that I've made a rename of a couple of tables using data migrations and apparently everything went fine I even see the table names updated in the database.
But when I create a new data migration it always takes the original name of the table (xxxxes), not the latest (xxxxs) and I have to change manually the migration script to avoid the error:
Cannot find the object "dbo.xxxxs" because it does not exist or you do not have permissions.
And what is worse, the index controller now fails because when it tries the ToList() method it throws the following error:
An exception of type 'System.Data.Entity.Core.EntityCommandExecutionException' occurred in EntityFramework.SqlServer.dll but was not handled in user code
Additional information: An error occurred while executing the command definition. See the inner exception for details.
Being inner details:
{"Invalid object name 'dbo.xxxxs'."}
I've looked in the whole project to try to find the place where this tables are still referenced with the original name but I've found nothing.
Any idea about how to solve this??
EDIT
What I did, and maybe here is where everything broke is create a data migration like this and run it.
public partial class Update5 : DbMigration
{
public override void Up()
{
RenameTable("xxxxes", "xxxxs");
}
public override void Down()
{
}
}
I've seen that the Down() method should have just the opposite action, which I did not add...
You can try to add the table names via data-annotations.
Check this link
By default, EF will use the name of your class to name the table. If you changed the table name, EF will not know which class corresponds with which table. So if you add the name of the table with an annotation above the class, EF will know what to find.
new to MVC and EF. Trying to achieve the following:
A new site with individual user accounts
Create a DB table "Leagues" whereby when creating a new league the LeagueAdmin is an ApplicationUser
I followed this tutorial to try to achieve what i wanted. When i start the application I am able to register new users without issue. However, when I go to create a new league I get the following error:
"Model compatibility cannot be checked because the database does not contain model metadata. Model compatibility can only be checked for databases created using Code First or Code First Migrations."
I have tried many fixes i've read about but they tend to lead me down a path of increasingly complex errors. I feel like this should be simple enough that i'd like to understand this error first before tackling the next.
VS Project Source is here
Most probably, your database does not contain a _MigrationHistory table.
Add this code to your DbContext:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<IncludeMetadataConvention>();
}
Go to Package Manager Console by following View -> Other Windows -> Package Manager Console
And write following commands:
enable-migrations
add-migration InitialCreate
update-database
Alternatively;
You can add this code to your DbContext;
static LeagueContext()
{
Database.SetInitializer<LeagueContext>(
new DropCreateDatabaseAlways<LeagueContext>());
}
In the application I'm building the very first thing the client does is request the breeze metadata. If the database does not exist and entity framework needs to create the database it will not seed using the initializer configured with Database.SetInitializer.
If something else triggers EF to do a query against the dbcontext first then the database is seeded as expected.
I'm not sure if this is a bug or intended for some reason?
Thanks
I'm pretty sure the bug is on your end. I have no trouble retrieving metadata first at which point the database is created and seeded. Do it all the time.
You can see this for yourself in any of the Breeze Todo samples. Remember that your first Breeze client query always asks for metadata before processing your query so the first call to the server (in these samples) is always a request for metadata. These samples would not work if a request for metadata failed to generate the database.
The Todos sample initializes and seeds the database in a trivial way in the class ctor (the static ctor). Here's the entire TodosContext.cs
namespace Todo.Models {
using System.Data.Entity;
public class TodosContext : DbContext
{
// DEVELOPMENT ONLY: initialize the database
static TodosContext()
{
Database.SetInitializer(new TodoDatabaseInitializer());
}
public DbSet<TodoItem> Todos { get; set; }
}
}
To see it in action:
Show all files
Delete the *App_Data/todo.sdf* database
Set breakpoints on that constructor and on the methods of the Web API controller.
Run with debug (F5) ... you'll see the metadata endpoint hit first, then this static constructor.
Look at the *App_Data* folder in Windows Explorer and confirm that the database was created.
Continue ... you'll see the Todos query endpoint hit.
Continue ... the screen fills with seeded todos.
How are you doing it?
I have an ASP.NET MVC 4 project with Entity Framework 5, .NET 4.5 and Visual Studio 2012.
In my solution I've put all the models in a project called Model, all the Repositories and my DbContext in one more project called Data.
I activate the migrations in the Data project with the Enable-Migrations command. I decide to handle them manually. If I create a new migration with the Add-Migration command everything works very well. If, for example, I add a new column to a table, it works fine. I can see the new column in the database schema and I see the new record into the _MigrationHistory table.
At this point, with the new column created, I need to add this column to the right model. So, i add this method to my code-first model class and I run the project.
It delete my database, and init it with the initial migration.
I can't tweak a model without loosing all data.
How I can avoid this behavior?
Thanks
UPDATE:
Configuration.cs
namespace NegoziazioneEventi.Data.Migrations
{
using System;
using System.Data.Entity;
using System.Data.Entity.Migrations;
using System.Linq;
internal sealed class Configuration : DbMigrationsConfiguration<NegoziazioneEventi.Data.NeDataContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
}
protected override void Seed(NegoziazioneEventi.Data.NeDataContext context)
{
}
}
}
Application_Start() in Global.asax
protected void Application_Start()
{
// init basic data on database
System.Data.Entity.Database.SetInitializer(new Models.InitData());
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
_container = Bootstrapper.GetWindsorContainer();
}
I decide to handle them manually. If I create a new migration with the Add-Migration command everything works very well.
...
At this point, with the new column created, I need to add this column to the right model. So, i add this method to my code-first model class and I run the project.
That is completely wrong usage of migrations and it is also the reason why EF deletes your database. You must first add property to model and then add migration because EF needs to store correct data into _MigrationHistory table to match that record with the real meaning of that migration.
With your current approach EF runs the application and checks _MigrationHistory table but the record in the table doesn't contain information about your newly added property so EF believes that new change was done to your model and uses default strategy to delete database and create a new one reflecting your current model. You can turn off this behavior but you should start by using migrations correctly!
To turn off the behavior use:
Database.SetInitializer<YourDatabaseContext>(null);
You are using your own initializer which is most probably derived from wrong build-in initializer causing drop of your current database.
I'm using the new migrations in my ASP.NET MVC 4 project and within the Migrations/Configuration file I have the following:
public Configuration()
{
AutomaticMigrationsEnabled = false;
AutomaticMigrationDataLossAllowed = false;
}
In the same file file, I also have a Seed method that populates my database. I've noticed that every time I run my app, it reseeds the database even though the model hasn't changed. Within my global.asax file I have the following Database Initializer in Application_Start
Database.SetInitializer(new MigrateDatabaseToLatestVersion<UtilitiesContext, Migrations.Configuration>());
I only want it to seed the database if the model changes or I run the Update-Database command. How would I go about doing that?
What about DropCreateDatabaseIfModelChanges? See this MSDN article. This will only reseed if the database is different than the model.
Usage:
Database.SetInitializer(new DropCreateDatabaseIfModelChanges<UtilitiesContext>());
Actually I just removed the initializer statement all together and it worked.