Entity Framework 4.1 "Code First" SetInitializer not being called again after Database.Delete - entity-framework

Trying to do some unit testing with EF 4.1 code first. I have my live db (SQL Server) and my unit test DB( Sql CE). After fighting (and losing) with EF, Sql CE 4.0 and Transaction support I decided the simplest way to run my test was to:
Create Db
Run Test
Delete Db
Rinse and repeat
I have my [Setup] and [TearDown] functions:
[SetUp]
public void Init()
{
System.Data.Entity.Database.SetInitializer(new MyTestContextInitializer());
_dbContext = ContainerFactory.Container.GetInstance<IContext>();
_testConnection = _dbContext.ConnectionString;
}
[TearDown]
public void Cleanup()
{
_dbContext.Dispose();
System.Data.Entity.Database.Delete(_testConnection);
}
Issue is that System.Data.Entity.Database.SetInitializer does not call MyTestContextInitializer after the first test.
Hence the 2nd test then fails with:
System.Data.EntityException : The
underlying provider failed on Open.
----> System.Data.SqlServerCe.SqlCeException
: The database file cannot be found.
Check the path to the database
TIA for any pointers

I got around this by calling 'InitializeDatabase' manually. Like so:
[SetUp]
public void Init()
{
var initializer = new MyTestContextInitializer();
System.Data.Entity.Database.SetInitializer(initializer);
_dbContext = ContainerFactory.Container.GetInstance<IContext>();
initializer.InitializeDatabase((MyTestContext)_dbContext);
_testConnection = _dbContext.ConnectionString;
}
[TearDown]
public void Cleanup()
{
System.Data.Entity.Database.Delete(_testConnection);
_dbContext.Dispose();
}
I think it may be a bug with EF 4.1 RC.

It's not a bug, the initializer set with
System.Data.Entity.Database.SetInitializer
is only called when the context is created for the first time in the AppDomain. Hence, since you're running all your tests in a single AppDomain, it's only called when the first test is ran.

It took me almost a day to find out what caused my strange unittest behaviour: the database connection stayed open or the database was not created with a every new test. I searched everywhere for the root of the cause: MSTest (no Admin rights or where working copies of files somehow deleted?), SQL Server Express/CE (login failure?), Unity (objects not disposed?) or Entity Framework (no proper database initialization?). It turned out to be EF. Thanks a lot for the answer!

Related

How To Unit Test Entity Framework With Seeded Data

I'm thinking that it makes sense to test my VS2015 EF Code First project with the data that gets created with seeding. It's not clear to me what should be in the test project in terms of setup and teardown and the actual tests.
Is there an example someone can point me at that shows this? Also, am I off base thinking this is a good way to test (seeded data). I have not been able to find examples of that. The examples I see seem a lot more complex with mocking data instead.
You haven't specified whether you are using MSTest or not, but I just had this problem today and this is what I did using MSTest. This base test class handles the seeding on the first test that runs. The Initialize(false) makes it that it wont try to initialize on secondary test runs so only the first test pays the setup price. Since each test is in a transaction they will rollback the changes made in each test.
[TestClass]
public abstract class EntityFrameworkTest
{
private static bool _hasSeeded;
protected TransactionScope Scope;
[TestInitialize]
public void Initialize()
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<YourContext, YourModelNameSpace.Migrations.Configuration>());
using (var context = new YourContext())
{
context.Database.Initialize(false);
if (!_hasSeeded)
{
context.AnEntity.AddOrUpdate(c => c.EntityName, new AnEntity {EntityName = "Testing Entity 1"});
context.SaveChanges();
_hasSeeded = true;
}
}
Scope = new TransactionScope();
}
[TestCleanup]
public void CleanUp()
{
Scope.Dispose();
}
[AssemblyCleanup]
public static void KillDb()
{
using (var context = new YourContext())
context.Database.Delete();
}
}
It is also worth noting that I setup my test project app.config with a connection string like this that my context is set to look for (ConnStringName). The desire being here that each devs machine will just create a Testing db in their local db and wont have to fiddle with changing the connection string to something if their actual SQL instance setup is different. Also, depending on if you are VS 2015 or not, your local DB data source may vary.
<add name="ConnStringName" connectionString="Data Source=(localdb)\MSSQLLocalDB; Initial Catalog=DbNameTestingInstance; Integrated Security=True; MultipleActiveResultSets=True;Application Name=Testing Framework;" providerName="System.Data.SqlClient" />

Entity Framework telling me the model backing the context has changed

I have a weird problem with Entity Framework code first migrations. I've been using EF and code first migrations on a project for months now and things are working fine. I recently created a new migration and when running Update-Database a restored backup of my database I get this error:
The model backing the context has changed since the database was
created. Consider using Code First Migrations to update the database
The migration does something like the following:
public override void Up()
{
using (SomeDbContext ctx = new SomeDbContext())
{
//loop through table and update rows
foreach (SomeTable table in ctx.SomeTables)
table.SomeField = DoSomeCalculation(table.SomeField);
ctx.SaveChanges();
}
}
I'm not using the Sql() function because DoSomeCalculation must be done in C# code.
Usually when I get something like this is means that I have updated my model somehow and forgot to create a migration. However that's not the case this time. The weird thing is that the error isn't even occurring on a migration that I created a few days ago and had been working fine.
I looked a quite a few articles about this and they all seems to say call
Database.SetInitializer<MyContext>(null);
Doing that does seem to work, but my understanding (based on this article) is that doing that will remove EF's ability to determine when the database and model are out of sync. I don't want to do that. I just want to know why it thinks they are out of sync all of a sudden.
I also tried running Add-Migration just to see if what it thought changed about the model but it won't let me do that stating that I have pending migrations to run. Nice catch 22, Microsoft.
Any guesses as to what's going on here?
I'm wondering if maybe the fact that migration listed above is using EntityFramework is the problem. Seems like maybe since it's not the latest migration anymore, when EF gets to it tries to create a SomeDbContext object it checks the database (which is not fully up to date yet since we're in the middle of running migrations) against my current code model and then throws the "context has changed" error.
It's possibly related to your using EF within the migration. I'm not sure how you're actually managing this, unless you've set a null database initialiser.
If you need to update data within a migration, use the Sql function, e.g.
Sql("UPDATE SomeTable SET SomeField = 'Blah'");
You should note that the Up() method is not actually running at the time of doing the migration, it's simply used to set up the migration which is then run later. So although you may think you've done something in the migration above the bit where you're using EF, in reality that won't have actually run yet.
If you cannot refactor your calculation code so it can be written in SQL, then you would need to use some mechanism other than migrations to run this change. One possibility would be to use the Seed method in your configuration, but you would need to be aware that this does not keep track of whether the change has been run or not. For example...
internal sealed class Configuration : DbMigrationsConfiguration<MyContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
}
protected override void Seed(MyContext context)
{
// Code here runs any time ANY migration is performed...
}
}
I tried replacing the EntityFramework code with regular ADO.NET code and it seems to work. Here is what it looks like:
public override void Up()
{
Dictionary<long, string> idToNewVal = new Dictionary<long, string>();
using (SqlConnection conn = new SqlConnection("..."))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand("SELECT SomeID, SomeField FROM SomeTable", conn))
{
SqlDataReader reader = cmd.ExecuteReader();
//loop through all fields, calculating the new value and storing it with the row ID
while (reader.Read())
{
long id = Convert.ToInt64(reader["SomeID"]);
string initialValue = Convert.ToString(reader["SomeField"]);
idToNewVal[id] = DoSomeCalculation(initialValue);
}
}
}
//update each row with the new value
foreach (long id in idToNewVal.Keys)
{
string newVal = idToNewVal[id];
Sql(string.Format("UPDATE SomeTable SET SomeField = '{0}' WHERE SomeID = {1}", newVal, id));
}
}

The model backing the 'DataContext' context has changed since the database was created

I am trying to use Code First with Migrations. Even though there are no current changes to my model, I'm getting an exception. When I add a migration, the up and down are empty, but I get a runtime error with the message as follows:
An exception of type 'System.InvalidOperationException' occurred in
EntityFramework.dll but was not handled in user code
Additional information: The model backing the 'MyDataContext' context
has changed since the database was created. Consider using Code First
Migrations to update the database (http://go.microsoft.com/fwlink/?
My architecture is as follows:
DataAccess project that includes the context, fluid configurations and migrations code
Model project that contains the poco classes
Web API and MVC projects that each contain the connections string in their respective web.config files.
Additionally I have the following code:
DbInitializer
public static MyDataContext Create()
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyDataAccess.MyDataContext, MyDataAccess.Migrations.Configuration>());
return new MyDataContext(ConfigurationManager.ConnectionStrings["MyDataContext"].ConnectionString, null);
}
I started with AutomaticMigrationsEnabled = false; in the migration Configuration constructor, as it was my understanding that this would allow (and require) me to have more control over when migrations were applied. I have also tried setting this to true but with the same result.
I added a new migration upon receiving this error, and the Up method was empty. I updated the database to this new migration, and a record was created in the _migrationHistory table, but I still receive the error when I attempt to run the application. Also, the seed data was not added to the database.
protected override void Seed(MyDataAccess.MyDataContext context)
{
IdentityResult ir;
var appDbContext = new ApplicationDbContext();
var roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(appDbContext));
ir = roleManager.Create(new IdentityRole("Admin"));
ir = roleManager.Create(new IdentityRole("Active"));
ir = roleManager.Create(new IdentityRole("InActive"));
var userNamager = new UserManager<User>(new UserStore<User>(appDbContext));
// assign default admin
var admin = new User { UserName = "administrator", Email = "myAdmin#gmail.com" };
ir = userNamager.Create(admin, "myp#55word");
ir = userNamager.AddToRole(admin.Id, "Admin");
}
where
public class ApplicationDbContext : IdentityDbContext<User>
{
public ApplicationDbContext()
: base("MyDataContext", throwIfV1Schema: false)
{
}
...
The question: If Add-Migration isn't seeing any change in the model, why do I get this error when I run? Why isn't the seed code being hit? How do I fix this, or if that can't be determined, how do I further determine the root cause?
I am not sure if you found the answer to your problem, but this other answer I found here actually did it for me:
Entity Framework model change error
I actually ended up deleting the __MigrationHistory table in SQL Server which I didn't know it was being created automatically.
The article also talks about the option to not generate it I think by using this instruction: Database.SetInitializer<MyDbContext>(null); but I have not used it, so I am not sure if it works like that
This worked for me.
Go to Package Manager Console and Run - Update-Database -force
I bet your data context is not hooking up the connection string.
Check if it's not initialized with a localdb (something like (localdb)\v11.0) and not working with that when you might think it's set to something else.
My issue ended up being a conflict between Automatic Migrations being enabled and the initializer MigrateDatabaseToLatestVersion as described here.

Debug code-first Entity Framework migration codes

I'm using Entity Framework code first in my website and I'm just wondering if there is any way to debug the migration codes. You know, like setting breakpoints and stuff like this.
I'm using Package Manager Console to update the database using Update-Database.
Thanks
I know that EF Code First Migrations is relatively new tool but don't forget about you are still in .NET.
So you can use:
if (System.Diagnostics.Debugger.IsAttached == false)
{
System.Diagnostics.Debugger.Launch();
}
After that you can see your InnerException.
Or you can use try...catch statement like this:
Exception handling Entity Framework
To hit a break point in a db migration set the context to MigrateDatabaseToLatestVersion on initialise.
Database.SetInitializer(new MigrateDatabaseToLatestVersion<EnterContextHere, Configuration>());
Then you just debug as normal (run using f5) and the breakpoint will hit the first time you run the project.
The problem now is that if you debug a second time the migration will not run. This is because the __MigrationHistory table has been updated to say you have migrated to the latest version. To re-test the migration open the package manager console and downgrade to the previous migration:
Update-Database –TargetMigration: ThePreviousMigrationName
My answer might be a bit silly but anyway here it goes.
If you, like me, some times have problems in the Seed() method what I usually do is simply create a public method that calls the Protect Seed().
public void SeedDebug(AppDbContext context)
{
Seed(context);
}
then in my HomeController I call this method in Debug mode.
public class HomeController : Controller
{
var appDb = new AppDbContext();
public ActionResult Index()
{
var config = new Configuration();
config.SeedDebug(appDb);
return View();
}
}
I know it's a bit lame solution, but it's simple and quick.
Of course this has to be done after the model been created.
So step by step:
comment the seed method and execute the update-database to create the model
uncomment the method Seed() and plugin the "hack" I mentioned above.
in the configuration disable Auto migrations
AutomaticMigrationsEnabled = false;//if you have this disabled already skip this step
Debug your application, fix the error and remove the "hack"
Here's a more fail-proof method which will do the trick without much fuss:
Step#1: Place this piece of code right above the migration you want to debug:
public partial class ORACLE_Test : DbMigration
{
public override void Up()
{
if (!System.Diagnostics.Debugger.IsAttached)
System.Diagnostics.Debugger.Launch();
AddColumn("TEST", "UR_USER_ID", x => x.Decimal(nullable: false, precision: 11, scale: 0, storeType: "number"));
AddColumn("TEST", "UR_CLIENT_ID", x => x.Decimal(nullable: false, precision: 11, scale: 0, storeType: "number"));
[...]
}
public override void Down()
{
}
}
Step#2: Compile the project containing your migrations
Step#3: Open a console inside the output directory (/bin/Debug, /bin/Release etc) containing the dll of your migrations
Step#4: Invoke migrate.exe with the /scriptFile parameter to launch the debugger and actually debug the desired db-migration
migrate.exe "Your.Migrations.Assembly.dll" /scriptFile="foo.sql" /verbose /startupConfigurationFile="Your.Migrations.Assembly.config"
Once the debugger-selector dialog pops up pick the visual studio instance that you have already opened.
You could add Console.WriteLine statements to the migration code (not a great solution)
Note, the messages are only shown if you run the migration code using the migrate.exe utility (in pacakges\EntityFramework.x.y.z\tools). They will not display if you run the migration through the Package Manager console.
I've had lots of luck using "Debugger.Launch()" (like in m_david's answer above) elsewhere, but inside of CreateDbContext it seems to somehow both attach, and not attach. What I mean is, it attaches and starts trying to step into .asm files and .cpp files (internal code). If I try to set a breakpoint on a Console.Writeline that I KNOW gets executed afterwards (I can see the output from ANY "dotnet ef migrations COMMAND") it both executes it and never hits the breakpoint.
This is what worked for me instead:
while (!System.Diagnostics.Debugger.IsAttached)
System.Threading.Thread.Sleep(10);
// Breakpoint after this...
You can execute the migration and manually attach using Visual Studio and it will actually let you step through the code like you expect, it's just more of a pain. What I should really try is the combination of both methods...
I also found a neat trick here to get the error details...
Basically, the trick is to grab all the information from an exception, put it in a string and throw a new DbEntityValidationException with the generated string and the original exception.

How do I recreate DB using EF4 code first for test

I'm using Entity Framework 4 Code First in my .net MVC 2.0 project and I'm having hard times to get my DB sync with my Entities. What I want is a page that I can call, as an exemple : /DB/Recreate, that would drop my current DB and recreate an empty one. Currently in my global.asax I have
protected override void OnApplicationStarted()
{
Database.SetInitializer(new CreateDatabaseOnlyIfNotExists<CorpiqDb>());
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
RegisterAllControllersIn(Assembly.GetExecutingAssembly());
}
I try to switch my database initializer in my action but I'm realy not sure, since it should already been initialized, that I'm using the right approach :
Database.SetInitializer(new AlwaysRecreateDatabase<CorpiqDb>());
var bidon = _session.All<Admin>();
Database.SetInitializer(new CreateDatabaseOnlyIfNotExists<CorpiqDb>());
bidon = _session.All<Admin>();
I don'y realy know how to do this, thank you for the help!
Ok I found a solution :
var dbContext = new CorpiqDb().Database ;
dbContext.Delete();
dbContext.Initialize();
dbContext.EnsureInitialized();
Database.SetInitializer(new CreateDatabaseOnlyIfNotExists<CorpiqDb>());
This will drop my database and create a new one that reflect the latest models, I can even seed the database with some data for my test.