I am using ef core in project and my repository calls a stored procedure to get the results. I was wondering if I can use inMemorydatabase feature of ef core to test against my repository.
You can but you should not do it. From Microsoft:
EF Core comes with an in-memory database that we use for internal
testing of EF Core itself. This database is in general not suitable
for testing applications that use EF Core. Specifically:
It is not a relational database.
It doesn't support transactions.
It cannot run raw SQL queries.
It is not optimized for performance.
None of this is very important when testing EF Core internals because
we use it specifically where the database is irrelevant to the test.
On the other hand, these things tend to be very important when testing
an application that uses EF Core.
https://learn.microsoft.com/en-us/ef/core/testing/#approach-3-the-ef-core-in-memory-database
Microsoft recommends using SQLite in-memory database instead. Always remember its lifetime though:
The database is created when the connection to it is opened
The database is deleted when the connection to it is closed
Sample:
public class SqliteInMemoryItemsControllerTest : ItemsControllerTest, IDisposable
{
private readonly DbConnection _connection;
public SqliteInMemoryItemsControllerTest()
: base(
new DbContextOptionsBuilder<ItemsContext>()
.UseSqlite(CreateInMemoryDatabase())
.Options)
{
_connection = RelationalOptionsExtension.Extract(ContextOptions).Connection;
}
private static DbConnection CreateInMemoryDatabase()
{
var connection = new SqliteConnection("Filename=:memory:");
connection.Open();
return connection;
}
public void Dispose() => _connection.Dispose();
}
https://learn.microsoft.com/en-us/ef/core/testing/sqlite#using-sqlite-in-memory-databases
Related
I have a WebApi setup and due to some reasons, I am facing performace issues with some of the api methods.
I would like to use MiniProfiler and to test the performance of these API methods and log the statistics delivered by Miniprofiler in to a Table.
The miniprofiler docs asks to add the follwing code,
using StackExchange.Profiling.Data;
...
public static MyModel Get()
{
var conn = new EFProfiledDbConnection(GetConnection(), MiniProfiler.Current);
return ObjectContextUtils.CreateObjectContext<MyModel>(conn);
}
Can somebody help me where actually this needs to be added, how the table will be Created and configured?
N.B: I am using EF 5 with Object Context Database First approach(Not DbContext)
Question is about: EntityFramework 6 CODE FIRST, Sql Server 2012
How can i detect that database schema changed and not compatible with current EF model?
I'm talking about production server and application. Default initializer is 'null', and it doen't update production database automatically, of course.
But if database schema changes, and no more compatible with my model, i want application must detect it on program startup. It is possible to do it manually.
If i'm not wrong, EntityFramework stores current schema on the __MigrationHistory table, and verifies it on the first context related operation, but not with 'null' initializer. From this reason, I want to do it manually on application startup.
I assume EntityFramework has related functions, i hope they are not private and i can use them.
(I have a problem caused by manual database schema change on one of our clients today)
Update: In fact, database schema changes occured by running same applications update tsql script, but applications itself is not updated.
Use custom initializer to accomplish this task.
public class ValidateDatabase<TContext> : IDatabaseInitializer<TContext>
where TContext : DbContext
{
public void InitializeDatabase(TContext context)
{
if (!context.Database.Exists())
{
throw new ConfigurationException( "Database does not exist");
}
else
{
if (!context.Database.CompatibleWithModel(true))
{
throw new InvalidOperationException("The database is not compatible with the entity model.");
}
}
}
}
I am using the Entity Framework POCOs to assist with migrating data from a legacy database to a new database. Both databases already exist and the Entity Framework has no part in creating or modifying structure for either. I created a sample database on the migration server and restored it to my local computer sql server (entirely in t_sql, no EF) and my context and its data classes are working fine and returning the data I want. Today I went to the production migration server and when I go to run my first test I get the above referenced error.
All I am doing is reading data, no writing, so this makes no sense to me. EF must be doing something when it hooks up the data context that I can't see. The error is coming from SqlClient.SqlConnection. There is no inner exception, no help link and nothing in the call stack except my method
Any ideas where to start looking?
Pamela
So it turns out the Entity Framework gets mad when the database changes at any point. You need to tell it to ignore the database. I did it by creating this base class for my data contexts
enter code here public class BaseContext<TContext> : DbContext where TContext : DbContext
{
protected BaseContext()
: base("Foxpert.HS.ChangeDetection.VHSContext")
{
Database.SetInitializer<TContext>(null);
Configuration.AutoDetectChangesEnabled = false;
}
}
My development DB is 2008 R2 which is where Code First generates the local database with DropCreateIfModelChanges.
My method of deploying to production is to generate scripts from local DB, including data and run that in production. This creates all of the tables, including the EdmMetadata table and populates it with the hash.
Works:
Run script in a different 2008 R2 instance, change connection string for the Entity model to point to this production instance, run application.
Does not work:
Run script in a different 2005 instance, change connection string for the Entity model to point to this production instance, run application. I get an error indicating the model has changed.
I think this doesn't work because the DB compatibility version is a part of the hash. thus in production it generates a hash and compares it to the hash stored in the EdmMetadata table. The new hash is different because it is generated against a 2005 DB.
I am guessing I would not have this problem if I was generating a 2005 DB locally and deploying that to a 2005 production instance. However I don't have 2005 installed and would rather not require all the developers to have to install it, when 2008 supports a 2005 compatibility mode already.
How can I force EF to generate a DB in 2005 compatibility mode?
If the only problem is the model compatibility check, then you can disable database initializers for your context when running in the production environment where you presumably don't need to initialize the database anyway. You can do this in code like so:
Database.SetInitializer<MyContext>(null);
But it's probably better to do it in the app.config/web.config for your production application like so:
<entityFramework>
<contexts>
<context type="MyNamespace.MyContext, MyAssembly" disableDatabaseInitialization="true" />
</contexts>
</entityFramework>
You will need to update to EF 4.3 for this syntax--see http://blogs.msdn.com/b/adonet/archive/2012/01/12/ef-4-3-configuration-file-settings.aspx. There is also a way to do it in EF 4.1: See http://blog.oneunicorn.com/2011/03/31/configuring-database-initializers-in-a-config-file/.
You could also try just updating to to EF 4.3 which doesn't use the EdmMetadata table anymore--it uses the __MigrationHistory table instead. This checks for model compatibility in a different way. It may still flag a difference if Code First would have generated a different database for 2005 than it did for 2008, which is occasionally the case.
You could install SQL Server 2005 Express on your dev box. It's free and would match your production environment better.
Finally, if none of the above work and you need to force Code First to generate a 2005 model/database, then you can do that, but it means using lower-level building blocks. First, you'll need to create the DbModelBuilder yourself and call Entity for each of the entity types for which you have a DbSet declared on your context:
var modelBuilder = new DbModelBuilder();
modelBuilder.Entity<User>();
modelBuilder.Entity<Blog>();
You can do other fluent configuration here or use data annotations as normal. OnModelCreating will not be called so don't put fluent calls there--move them here instead.
Once you have a configured DbModelBuilder you'll need to build and compile to get a compiled model that can be passed to DbContext. It is at this stage that you can pass in "2005" as the provider manifest token.
var compiledModel = modelBuilder
.Build(new DbProviderInfo("System.Data.SqlClient", "2005"))
.Compile();
You should now cache this compiled model in your app domain so that you only build and compile it once. (Normally DbContext does this for you when it builds the model, but if you build the model yourself then you need to also do the caching yourself.)
Finally, you will need to pass the compiled model to a constructor of your context every time you need to use it and have that constructor pass the model on to the base constructor.
public class MyContext : DbContext
{
public MyContext(DbCompiledModel model)
: base(model)
{
}
public DbSet<User> Users { get; set; }
public DbSet<Blog> Blogs { get; set; }
}
There are other constructor overloads for passing a name or connection string as well if you need them.
If you have a system that has multiple types of object contexts. For Eg: BillingObjectContext, HumanResourceObjectContext etc. All derive from ObjectContext but ObjectContext Class does not implement any specific interface like IObjectContext. How would you apply DI/IoC in case of multiple types of ObjectContext say using Ninject?
If you must depend on it in a test, you have to mock it. Here's a sample; it's not much harder than implementing an interface. See also TDD improvements in EF 4.
Why can't we just create the actual context object to be used in our tests? Since we don't want our tests to affect the production database, we can always specify a connection string that points to a test database. Before running each test, construct a new context, add the data you will need in your test, proceed with the unit test, then in the test cleanup section, delete all the records that were created during the test. The only side-affect here would be that the auto-increment IDs would be used up in the test database, but since it's a test database - who cares?
I know that most answers regarding this question propose using DI/IoC designs to create interfaces for data contexts etc. but the reason I am using Entity Framework is exactly to not write any interfaces for my database connections, object models, and simple CRUD transactions. To write mock interfaces for my data objects and to write complex queryable objects to support LINQ, defeats the purpose of relying on highly-tested and reliable Entity Framework.
This pattern for unit testing is not new - Ruby on Rails has been using it for a long time and it's worked out great. Just as .NET provides EF, RoR provides ActiveRecord objects and each unit test creates the objects it needs, proceeds with the tests, and then deletes all the constructed records.
How to specify connection string for test environment? Since all tests are in their own dedicated test project, adding a new App.Config file with a connection string for the test database would suffice.
Just think of how much headache and pain this will save you.
namespace ProjectNamespace
{
[TestClass]
public class UnitTest1
{
private ObjectContext objContext;
[TestInitialize]
public void SetUp()
{
// Create the object context and add all the necessary data records.
}
[TestMethod]
public void TestMethod1()
{
// Runs the tests.
}
[TestCleanup]
public void CleanUp()
{
// Delete created records.
}
}
}