How To Unit Test Entity Framework With Seeded Data - entity-framework

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" />

Related

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.

EntityFramework with Repository Pattern and no Database

I have a web api project that I'm building on an N-Tier system. Without causing too many changes to the overall system, I will not be touching the data server that has access to the database. Instead, I'm using .NET remoting to create a tcp channel that will allow me to send requests to the data server, which will then query the database and send back a response object.
On my application, I would like to use entity framework to create my datacontexts (unit of work), then create a repository pattern that interfaces with those contexts, which will be called by the web api project that I created.
However, I'm having problems with entity framework as it requires me to have a connection with the database. Is there anyway I can create a full entity framework project without any sqlconnections to the database? I just need dbcontexts, which I will be mapping my response objects and I figure that EF would do what I needed (ie help with design, and team collabs, and provide a nice graphical designer); but it throws an error insisting that I need a connection string.
I've been searching high and low for tutorials where a database is not needed, nor any sql connection string (this means no localdb either).
Okay as promised, I have 3 solutions for this. I personally went with #3.
Note: Whenever there is a repository pattern present, and "datacontext" is used, this is interpreted as your UnitOfWork.
Solution 1: Create singletons to represent your datacontext.
http://www.breezejs.com/samples/nodb
I found this idea after going to BreezeJS.com's website and checked out their samples. They have a sample called NoDb, which allows them to create a singleton, which can create an item and a list of items, and a method to populate the datacontext. You create singletons that would lock a space in memory to prevent any kind of thread conflicts. Here is a tid bit of the code:
//generates singleton
public class TodoContext
{
static TodoContext{ }
private TodoContext() { }
public static TodoContext Instance
{
get
{
if (!__instance._initialized)
{
__instance.PopulateWithSampleData();
__instance._initialized = true;
}
return __instance;
}
}
public void PopulateWithSampleData()
{
var newList = new TodoItem { Title = "Before work"};
AddTodoList(newList);
var listId = newList.TodoListId;
var newItem = new TodoItem {
TodoListId = listId, Title = "Make coffee", IsDone = false };
AddTodoItem(newItem);
newItem = new TodoItem {
TodoListId = listId, Title = "Turn heater off", IsDone = false };
AddTodoItem(newItem);
}
//SaveChanges(), SaveTodoList(), AddTodoItem, etc.
{ ... }
private static readonly Object __lock = new Object();
private static readonly TodoContext __instance = new TodoContext();
private bool _initialized;
private readonly List<TodoItem> _todoLists = new List<TodoItem>();
private readonly List<KeyMapping> _keyMappings = new List<KeyMapping>();
}
There's a repository included which directs how to save the context and what needs to be done before the context is saved. It also allows the list of items to be queryable.
Problem I had with this:
I felt like there was higher maintenance when creating new datacontexts. If I have StateContext, CityContext, CountryContext, the overhead of creating them would be too great. I'd have problems trying to wrap my head around relating them to each other as well. Plus I'm not too sure how many people out there who agree with using singletons. I've read articles that we should avoid singletons at all costs. I'm more concerns about anyone who'd be reading this much code.
Solution 2: Override the Seed() for DropCreateDatabaseAlways
http://www.itorian.com/2012/10/entity-frameworks-database-seed-method.html
For this trick, you have to create a class called SampleDatastoreInitializer that inherits from System.Data.Entity.DropCreateDatabaseAlways where T is the datacontext, which has a reference to a collection of your POCO model.
public class State
{
[Key()]
public string Abbr{ get; set; }
public string Name{ get; set; }
}
public class StateContext : DbContext
{
public virtual IDbSet<State> States { get; set; }
}
public class SampleDatastoreInitializer : DropCreateDatabaseAlways<StateContext>
{
protected override void Seed (StateContext context)
{
var states = new List<State>
{
new State { Abbr = "NY", Name = "New York" },
new State { Abbr = "CA", Name = "California" },
new State { Abbr = "AL", Name = "Alabama" },
new State { Abbr = "Tx", Name = "Texas" },
};
states.ForEach(s => context.States.Add(s));
context.SaveChanges();
}
}
This will actually embed the data in a cache, the DropCreateDatabaseAlways means that it will drop the cache and recreate it no matter what. If you use some other means of IDatabaseInitializer, and your model has a unique key, you might get an exception error, where you run it the first time, it works, but run it again and again, it will fail because you're violating the constraints of primary key (since you're adding duplicate rows).
Problem I had with this:
This seems like it should only be used to provide sample data when you're testing the application, not for production level. Plus I'd have to continously create a new initializer for each context, which plays a similar problem noted in solution 1 of maintainability. There is nothing automatic happening here. But if you want a way to inject sample code without hooking up to a database, this is a great solution.
Solution 3: Entity framework with Repository (In-memory persistence)
I got this solution from this website:
http://www.roelvanlisdonk.nl/?p=2827
He first sets up an edmx file, using EF5 and the code generator templates for EF5 dbcontexts you can get from VS extension libraries.
He first uses the edmx to create the contexts and changes the tt templates to bind to the repository class he made, so that the repository will keep track of the datacontext, and provide the options of querying and accessing the data through the repository; in his website though he calls the repository as MemoryPersistenceDbSet.
The templates he modified will be used to create datacontexts that will bind to an interface (IEntity) shared by all. Doing it this way is nice because you are establishing a Dependency Injection, so that you can add any entity you want through the T4 templates, and there'd be no complaints.
Advantage of this solution:
Wrapping up the edmx in repository pattern allows you to leverage the n-tier architecture, so that any changes done to the backend won't affect the front end, and allows you to separate the interface between the front end and backend so there are no coupled dependencies. So maybe later on, I can replace my edmx with petapoco, or massive, or some other ORM, or switch from in-memory persistence to fetching data from a database.
I followed everything exactly as explained. I made one modification though:
In the t4 template for .Context.tt, where DbSetInConstructor is added, I had the code written like this:
public string DbSetInConstructor(EntitySet entitySet)
{
return string.Format(
CultureInfo.InvariantCulture,
“this.{1} = new BaseRepository();”,
_typeMapper.GetTypeName(entitySet.ElementType), entitySet);
}
Because in my case I had the entityset = Persons and entityname = Person. So there’d be discrepancy. But this should cover all bases.
Final step:
So whether you picked solution 1, 2, or 3. You have a method to automatically populate your application. In these cases, the stubs are embedded in the code. In my case, what I've done is have my web server (containing my front end app), contact my data server, have the data server query the database. The data server will receive a dataset, serialize it, and pass it back to the web server. The web server will take that dataset, deserialize it, and auto-map to an object collection (list, or enumberable, or objectcollection, etc).
I would post the solutions more fully but there's way too much detail between all 3 of these solutions. Hopefully these solutions would point anyone in the right direction.
Dependency Injection
If anyone wants some information about how to allow DI to api controllers, Peter Provost provides a very useful blog that explains how to do it. He does a very very good job.
http://www.peterprovost.org/blog/2012/06/19/adding-ninject-to-web-api/
few more helpful links of repository wrapping up edmx:
http://blogs.msdn.com/b/wriju/archive/2013/08/23/using-repository-pattern-in-entity-framework.aspx
http://www.codeproject.com/Articles/688929/Repository-Pattern-and-Unit-of

Entity Framework DefaultConnectionFactory being ignored

I'm using Entity Framework 5 with Code First. I've written a custom IDbConnectionFactory which I want to use for all the connections made by my DbContext class, so early on in the application's lifecycle, before any database work is done, I call
Database.DefaultConnectionFactory = new MyConnectionFactory();
However, MyConnectionFactory.CreateConnection is never called, which suggests to me that EF's changed it back - but the debugger shows that it's still a MyConnectionFactory after several queries have run. For some reason, it's just not using it.
My DbContext is initialised by passing the name of a connection string from the app.config file, and those connection strings do specify an explicit provider (as indeed they have to) so I'm wondering if that's causing a per-connection override of the connection factory based on the connection string. Does this happen and can I stop it without registering a completely new provider (although maybe that's not too hard to do?).
Whatever I see online about this (much obscured by the defaultConnectionFactory tag in various app.config examples) suggests you can just change it to an IDbConnectionFactory instance of your choice and it'll work, but mine isn't behaving.
The purpose of this is to allow me to run a particular set of SQL statements whenever a new connection is opened, so the second part of this question would be does anybody know a better way to do this?
I know it is not ideal but this worked for me:
public class DBBase : DbContext
{
public DBBase(string nameOrConnectionString)
: base(Database.DefaultConnectionFactory.CreateConnection(nameOrConnectionString), true)
{
}
// ...
}
You need to get the connection that you built for each call that you are wanting to use. For example using the following code.
private static void UsingCustomConnection()
{
using (var conn = Database.DefaultConnectionFactory.CreateConnection("YourDbName"))
{
using (var context = new YourContext(conn))
{
context.Destinations.Add(new Destination {Name = "Colorado"});
context.SaveChanges();
}
}
}
You will need to setup this in YourContext
public YourContext(DbConnection connection)
: base(connection, contextOwnsConnection: false)
{
}

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

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!