Entity Framework 5 Migrations: Setting up an initial migration and single seed of the database - asp.net-mvc

I have an MVC4 app which I've recently upgraded to Entity Framework 5 and I am trying to move our database over to using migrations from the development style of dropping and creating each run.
Here's what I've done in my app start function.
protected void Application_Start()
{
Database.SetInitializer(
new MigrateDatabaseToLatestVersion< MyContext, Configuration >() );
...
}
I ran the Enable-Migrations command on my repositories project and I thought that this would create an initial migration file however the only file it created was Configuration
When I delete the database it creates it as expected via code first and seeds the database from the Configuration file. In the configuration file I changed all the Add() functions to AddOrUpdate()
However it runs the seed function in my Configuration file each time the website starts and duplicates all the seed data again and again.
I imagined that it would create an initial migration file as the blog I read suggested that it would and I could put the seed data in there but it didn't
Can anyone explain how I should be setting up DB in code so that it only seeds once?
LINK: The migrations blog post I followed
While this is quite interesting for using the EF migrate.exe I've since switched to using roundhouse for running migrations. I still use EF to scaffold my migrations based on the models but I wrote a little console app to write the migrations out to SQL files. I then use roundhouse to perform the migrations themselves through my rake build scripts. There's a little more process involved but it's much more stable than using EF to perform the migrations on the fly when the application starts up.

This has proved to be a popular post so I have updated it in light of feedback from others. The main thing to know is that the Seed method in the Configuration class is run EVERY time the application starts, which isn't what the comment in the template method implies. See the answer from someone at Microsoft to this post about why that is - thanks to Jason Learmouth for finding that.
If you, like me, only want to run the database updates if there are any pending migrations then you need to do a bit more work. You can find that out if there are pending migrations by calling migrator.GetPendingMigrations(), but you have to do that in the ctor as the list of pending migrations is cleared before Seed method is called. The code to implement this, which goes in the Migrations.Configuration class is as follows:
internal sealed class Configuration : DbMigrationsConfiguration<YourDbContext>
{
private readonly bool _pendingMigrations;
public Configuration()
{
// If you want automatic migrations the uncomment the line below.
//AutomaticMigrationsEnabled = true;
var migrator = new DbMigrator(this);
_pendingMigrations = migrator.GetPendingMigrations().Any();
}
protected override void Seed(MyDbContext context)
{
//Microsoft comment says "This method will be called after migrating to the latest version."
//However my testing shows that it is called every time the software starts
//Exit if there aren't any pending migrations
if (!_pendingMigrations) return;
//else run your code to seed the database, e.g.
context.Foos.AddOrUpdate( new Foo { bar = true});
}
}
I should point out that some people have suggested putting the seed code in the actual 'up' migration code. This works, but means you need to remember to put the seed code in each new migration and its pretty hard remember so I wouldn't do that. However if your seed changes with each migration then that might be the a good way to go.

You could add a migration manually and fill it with whatever seeding code you want? In package manager console run:
Add-Migration [Name]
You can then edit that file which is created for you in your migrations folder.
In my project i actually do seeding like Richard though in the Seed method of the context configuration. I really have no preference. But migrations should be more efficient in that the application doesn't need to check if the rows exist in the database when the application starts. There is just the need to check if the migration has been run, which should be faster.
internal sealed class Configuration : DbMigrationsConfiguration<MyContext>
{
public Configuration()
{
// If you want automatic migrations as well uncomment below.
// You can use both manual and automatic at the same time, but I don't recommend it.
//AutomaticMigrationsEnabled = true;
//AutomaticMigrationDataLossAllowed = true;
}
protected override void Seed(MyContext context)
{
// This method will be called after migrating to the latest version.
// You can use the DbSet<T>.AddOrUpdate() helper extension method
// to avoid creating duplicate seed data.
context.FontFamilies.AddOrUpdate(
f => f.Id,
new FontFamily { Id = 1, PcName = "Arial" },
new FontFamily { Id = 2, PcName = "Times New Roman" },
});
I'm using this in Global.asax:
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
// Any migrations that haven't been applied before will
// automatically be applied on Application Pool restart
Database.SetInitializer<MyContext>(
new MigrateDatabaseToLatestVersion<MyContext,
MyApp.Migrations.Configuration>()
);
}
}

This is something I've wondered about in the past too. I have certain tables in my database which get populated in my Seed event, and now I just check to see if one of them is empty within the Seed method. If there are rows, the Seed method doesn't run. Not infallible, but does the trick.

The answer to this SO question explains why Seed runs every time the app runs.
I use Jon Smiths method, but I have put the check for pending migrations statement in an #if block like this:
#if (!DEBUG)
if (!_pendingMigrations) return;
#endif
That way when I'm debugging the Seed method always runs to repopulate my seed data - useful when I do deletes during testing, etc. but I don't get the perf hit when in release.

Related

EF Core repeatedly creating same migration, altering identity column and changing nothing

Recently I added a new data entity to my EFCore2.2 DbContext (within a net47 project) and attempted to generate a migration with the CLI tool as I have many times. On attempting to update the database the migration fails since the migration attempts to ALTER COLUMN on an identity column in an unrelated table. I removed the migration and removed the new entity and then ran add-migration, essentially with zero code changes. Sure enough, the same breaking AlterColumn calls, and nothing else, were generated (pointlessly, it seems) in the Up & Down methods. Here is the migration code:
public partial class ServerConfig : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<long>(
name: "ID",
table: "ProfileParams",
nullable: false,
oldClrType: typeof(long))
.OldAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<long>(
name: "ID",
table: "ProfileParams",
nullable: false,
oldClrType: typeof(long))
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
}
}
In the interest of eliminating extra factors, I reverted code back to just after this entity (ProfileParams) was originally added & migrations created. I tried add-migration from that point, and indeed, I got the same migration code as we see above (and no change in snapshot). I then reverted code back to just before the ProfileParams class was added, and generated the migration that actually created that table. It was identical to the full CREATE, and the snapshot was changed appropriately. But then I immediately ran add-migration again. Lo and behold I get the same extra "alter column" migration as above, and the next migration & the next will have it.
So essentially, going forward, it appears all future migrations will have this same "alter column" added in the up/down methods. Why?
In the interest of additional detail:
Various other tables have an ProfileParams navigation property which
EFCore picked up as a nullable foreign key.
Abbreviated bits of the snapshot:
modelBuilder.Entity("ProfileParams", b =>
{
b.Property<long>("ID")
.ValueGeneratedOnAdd();
b.HasKey("ID");
b.ToTable("ProfileParams");
});
modelBuilder.Entity("AssetUser", b =>
{
b.Property<string>("ID");
b.Property<long?>("ParamsID");
b.HasKey("ID");
b.HasIndex("ParamsID");
b.ToTable("AssetUsers");
});
modelBuilder.Entity("AssetUser", b =>
{
b.HasOne("ProfileParams", "Params")
.WithMany()
.HasForeignKey("ParamsID");
});
The problem is due to using uint for a primary key, and what looks like a bug in EF Core trying silently to work around this, and then silently failing in an obscure way.
In the case above, despite my detail I did not show the original entity class, but the ID in question was indeed of type uint. Answers to other questions suggest that EF Core does not support unsigned types, but it will certainly pretend to, and create a confusing situation such as this one! Instead of having an error on the initial migration (which does not apply the needed annotation for SQL auto-identity), it goes ahead and creates it.
This is what we would expect if the entity class simply had an ID of type long:
migrationBuilder.CreateTable(
name: "ProfileParams",
columns: table => new
{
ID = table.Column<long>(nullable: false)
/* But this part is missing when uint type is used! */
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
},
constraints: table =>
{
table.PrimaryKey("PK_ProfileParams", x => x.ID);
});
From there, and forever onward, on all future migrations it will attempt to fix its own omission by altering the column with the annotation. Oddly, though, even the "Down" function it generates suggests it already had the annotation since Up & Down are identical! But original migration and snapshot, and all subsequent snapshots fail to capture what the following migrations try to fix.
Presumably if the migration were tweaked and the table were actually dropped and recreated (not sure why EF Core thinks it can alter an identity column!) then the resulting SQL table would then have an auto-identity bigint key, but there would likely be issues populating the actual uint ID field from that value.
In short, just use a long key and it works. Wow.
Make sure you have NuGet package for only one provider.
I had (beside MSSQL) also MySql and Postgresql and it used the wrong one when using AddMigration.

my sqlite3 DB doesn't show column values in device but it does in simulator

My DB is not getting copied over to my device, but it does to the simulator.
Here is what I am doing:
Create a new sqllite3 db from terminal:
sqlite> create table myTable (id integer primary key, name text);
sqlite> insert into myTable (name) values ('john');
sqlite> select * from myTable;
1|john
This creates a db in this path: users/John/iosApp.db
Then I close the terminal and copy that db to my xamarin project and set its buildAction to 'content'.
Here is my model:
[Table("myTable")]
public class MyTable
{
[PrimaryKey, AutoIncrementAttribute, Column("id")]
public int ID {get; set;}
[Column("name")]
public string Name { get; set; }
}
And I do this to copy the db to the Document folder:
string pathToDatabase = "iosApp.db";
userPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), pathToDatabase);
File.Delete (userPath); // delete first and copy next
File.Copy (pathToDatabase, userPath);
var myDB = new SQLiteConnection (userPath);
MyTable myTable = myDB.Get<MyTable> (1);
then I run the app and I set a breaking point after the last line in the code above and I hover over the myTable:
if I am using the simulator, I see the schema and value of 1 for ID and 'john' for Name.
if I am using the device, I see the schema but 0 value for ID and null for Name!
Looking at the path when I am using the device, points to this:
"/private/var/mobile/Applications/277749D4-C5CC-4BF4-8EF0-23B23833FCB1/Documents/iosApp.db"
I loaded the files in using iFunBox and the db file is there with the exact size
I have tried all the following:
Clean All in the project
Rebuild All
removed the 'debug' folder from the project
restarted Xamarin
and even restart the machine
But still the same behavior, what else should I try to be able to see the values of ID and Name?
my sdk version is attached
UPDATE:
After a lot of changes and cleaning up, I managed to display the value of all columns except the identity column displayed as 0. Puzzled, I went back to the xamarin sample project: http://developer.xamarin.com/recipes/ios/data/sqlite/create_a_database_with_sqlitenet/
it displayed the value of the identity correctly.
Trying to bring in similar code to my project, but no success.
To role out the possibility of version issue, I went and downloaded the latest sqlite from this link:
http://components.xamarin.com/gettingstarted/sqlite-net/true
The same behavior... I created a whole new page in my project, used the references the sample used and only has the code to create a sample table. Same behavior, the identity value is displayed in the other project but not mine. This leads me to conclude that there is something completely is wacky in my project. Now I am considering creating a whole new project and move my files to the new one after making sure first that the piece of being able to see the value of my id in my model shown up. Stay toned, I will make sure to update this thread.
If you have any pointers, please share them
I couldn't find a solution to my problem, but I found an alternate method to create the DB that turns out to be even nicer than the original one.
One important thing to note is that in the original problem (details above), the DB code was working for months since I started developing the application. I don't know when it started behaving badly, but I suspect it was due to the download of the new Xamarin 3.0. I can't think of any other reason.
So, to solve my issue, There are two main things I did:
I followed this link on how to create DB and tables and do CRUD operations: http://components.xamarin.com/gettingstarted/sqlite-net/true
This method seems to be the newest way to create DB. It was: published on
June 24, 2014. It has an SQLite.dll, whereas my previous solution was using a SQLite.cs file. So, now I am creating my DB now at runtime.
Something didn't work still with the new method. It was giving me an object null exception error. I didn't spend much time investigating about it. When I provided values for my primary key and identity values, the error went away. Actually, this could have been the solution to my previous problem. I would have tried providing the identity values against the old code, if I am not already happier with the new method.
I hope this helps someone.

Entity Framework Code First - How do I tell my app to NOW use the production database once development is complete instead of creating a local db?

I'm using Code First with Entity Framework 5 using MVC4 and MVC Scaffolding (link/tutorial: http://www.codeproject.com/Articles/468777/Code-First-with-Entity-Framework-5-using-MVC4-and?msg=4531106#xx4531106xx) to create my database from my models. So, basically, when I run the app, the app drops and creates a new database if my model changes. That's great. Now, obviously, this is great for local development.
But what about when my app goes to production? How do I tell the code to NOT do this anymore, and rather point my app to use the database I have hosted on GoDaddy? I changed the connection string in the web.config to point to that of the GoDaddy database, but this isn't working. What happens is the code still tries to use the old connection string for some reason unknown to me. I can't seem to get my app to NOW use the database I created on GoDaddy. I'm starting to regret going down the code-first route....
Here's the line of code in my Application_Start method that auto-generates my database (in this case, only if my model changes):
System.Data.Entity.Database.SetInitializer(new System.Data.Entity.DropCreateDatabaseIfModelChanges<CapWorx.QuikCap.Models.CapWorxQuikCapContext>());
I found the solution to my problem.
Originally, I had the following in my context's constructor:
static CapWorxQuikCapContext()
{
Database.SetInitializer(new CodeFirstSeeder.Xml.DropCreateDatabaseAlways<CapWorxQuikCapContext>());
}
Note that the CodeFirstSeeder is irrelevant at this point- it's just a strategy I installed to seed some sample data. Anyways, I changed the above to be:
public CapWorxQuikCapContext()
: base("DefaultConnection")
{
}
This tells my app to look at the connection string called "DefaultConnection" and use it for its data source.
(as per our discussion / comments)
simple rule is -
If you have the 'non-static ctor' CapWorxQuikCapContext() : base("connection") - then you have to use that same name in the config as well.
Otherwise - you have to name the connection string the same as your Context class - i.e. exactly the CapWorxQuikCapContext.
If you don't - EF/CF makes its own 'connection' path - i.e. making some default db name - like your context - or like you have in the ctor

Entity Framework 4 SaveChanges Method not saving to database

I'm trying to use Entity Framework 4 for a small database application I'm writing to keep record of downloaded files. When running the application I set a break point after the tableName.Add() method, before the .SaveChanges() method and I can see the data saved into the entity; then I have another break point after calling the .SaveChanges() method, and look into the database to find there is no record saved to it. I have found a lot of similar questions, but I have not found the solution to my particular problem. Here is the code:
public void StartNewDownload(string FileID)
{
DateTime startTime = DateTime.Now;
FilesDBEntities db = new FilesDBEntities();
int startedID = (from dr in db.tblDownloadResults
where dr.Value.Equals("Started")
select dr.ResultID).First();
tblDownloads myDownload = new tblDownloads { FileID = FileID, StartDateTime = startTime, ResultID = startedID };
db.tblDownloads.Add(myDownload);
db.SaveChanges();
}
Any help is appreciated.
Thanks!
Pawel, you guided me in the right direction. The entity had the data, but the database I was looking into did not. But after reading your comment I ran the program from Visual Studio and used Process Monitor to monitor any operations to *.sdf files. This helped finding out that upon building the solution, it would create another database file to the bin\Debug folder. I forgot the database Build Action property was set as "Content".
Thanks!!
You can use SQL Server Profiler to see if the entity framework has really called the database.
(The tool is not included in SQL Server Express)

Changes not reflected in Database while using entity framework

I am accessing my database through ADO.NET Entity framework in MVC 3 Application.
I am updating my database through Stored Procedure.
But the changes are not reflected at run time.I mean to say i am able to see the changes only after restarting it.
What is the reason for the problem and How can i avoid it ?
I am using Repository pattern So at repository My code look like this
Ther Is One Function Which Save Changes
public void SaveNewAnswer(AnswerViewModel answer,string user)
{
SurveyAdminDBEntities _entities = new SurveyAdminDBEntities();
_entities.usp_SaveNewAnswer(answer.QuestionId, answer.AnswerName, answer.AnswerText, answer.AnswerOrder, answer.Status, user);
_entities.SaveChanges();
}
Data Retreival Code
public IEnumerableGetMultipleChoiceQuestions(string questionId)
{
SurveyAdminDBEntities _entities = new SurveyAdminDBEntities();
_entities.AcceptAllChanges();
_entities.SaveChanges();
return _entities.usp_GetMultipleChoiceQuestions(Int32.Parse(questionId));
}
But Changes are not reflected till the time i don't clode the session of the browser and run it again .
Please help !
Thank You In advance
Are you calling context.SaveChanges() on your Entities (DbContext/ObjectContext) object? Are you using a transaction that you haven't committed?
If you have an uncommitted transaction in your sproc, you can try creating your own entity transaction and seeing if committing your transaction will commit the nested transaction as well. The problem is that calling SaveChanges() automatically begins and commits a transaction, so this may not be any different than that.
I would also call _entities.AcceptAllChanges() in your save operation.
public void SaveNewAnswer(AnswerViewModel answer,string user)
{
SurveyAdminDBEntities _entities = new SurveyAdminDBEntities();
_entities.Connection.Open();
System.Data.Common.DbTransaction tran = _entities.Connection.BeginTransaction();
try
{
_entities.usp_SaveNewAnswer(answer.QuestionId, answer.AnswerName, answer.AnswerText, answer.AnswerOrder, answer.Status, user);
_entities.SaveChanges(); // automatically uses the open transaction instead of a new one
tran.Commit();
}
catch
{
tran.Rollback();
}
finally
{
if (_entities.Connection.State == System.Data.ConnectionState.Open)
_entities.Connection.Close();
_entities.AcceptAllChanges();
}
}
Is your stored procedure doing an explicit commit? Things run in a database session will be available for that session, but not available to any other session until the action is committed.
When you pull data out of your database into your context that data is kept in memory, separate from the actual database itself.
You will see the changes if you create a new context object instance and load the data from the database with it.
It's good practice to not use the same instance of your context object but create them on an as needed basis for individual transactions with the database. In your case if you're updating via function imports instead of the context.SaveChanges() method then you need to refresh your context with the updated data after you commit those changes.
Add this to your connect string (assuming sql 2005)
transaction binding=Explicit Unbind;
if the data is no longer available after session reset, then the problem is indeed with a transaction, if the data is then available after reset, then your problem is something different and we'll likely need more details.

Resources