This project has moved and is read-only. For the latest updates, please go here.

Using a DbContext generated with Entity Framework?

Mar 20, 2014 at 4:48 PM
Hi,

My situation is like this:
I have a project that I would like to test, in which I have generated an .edmx file from my database. The generated DbContext class in the Context.tt file is used quite a lot in my program, and I would have to use that in my tests as well.
I have created a Unit Test Project and tried to get Effort to work with the

In your tutorial you say that a fake DbContext should be created, which I did as so:
    class FakeMyAppContext : DbContext
    {
        public FakeMyAppContext(DbConnection connection) 
        : base(connection, true)
        {
        }
        
        public virtual DbSet<Table1> Table1 { get; set; }
        ...
}
But then I end up with another DbContext class, which I can't use for testing my methods.

I've been testing around doing different things.
First I tried letting FakeMyAppContext extend MyAppContext (the generated one), but I couldn't get that to work.
Secondly I created a partial class MyAppContext with the needed constructor, and tried to use that, but then I get a System.ArgumentException when I try to use the context in one of the methods I'm testing (GetDependencyOrder):
"The supplied connection is not valid because it contains insufficient mapping or metadata information. Parameter name: connection"

Part of my test class:
    private MyAppContext _context;

    [TestInitialize]
    public void TestInitialize()
    {
        EntityConnection connection = Effort.EntityConnectionFactory.CreateTransient("name=MyAppContext");

        using (var context = new MyAppContext(connection))
        {
            // Setting up test values...
        }
        _context = new MyAppContext(connection);
    }
    
    [TestMethod]
    public void GetDependencyOrder_fails_with_circular_dependencies()
    {
        List<LoadingTable> tables = LoadingTable.GetDependencyOrder(1, _context);
        ...
And the method in the LoadingTable class that it calls:
public static List<LoadingTable> GetDependencyOrder(int issid, MyAppContext context)
{
    List<LoadingTable> loadingTables = context.LoadingTable.Where(lt => lt.ImportSourceSystemID == issid).ToList();
    ...
The error probably has something to do with the connection string, which I had to copy from the actual project to the test project, but I'm just also wondering if I'm on the right track here...
Apr 6, 2014 at 9:48 PM
Hello,

The partial class technique is working for me. Didn't you forget to include the connection string in the test project? Could you provide me a little more info about the exception?
Apr 7, 2014 at 9:05 AM
Hi, tamasflamich. Thanks for your reply.

Good to hear that the partial class technique is a way to go, I was unsure about that and hadn't found anything about it here.

I copied the <connectionStrings> element from the original project's App.config to the test project's App.config, so it's there. I googled the exception and found people that came across the same problem (for example: http://www.newdavesite.com/part9/view/4073213), with the suggestion to change the * in my connection string to the assembly name. That didn't help, unfortunately. Still get the same exception.

The connectionStrings element in the test project's App.config:
<connectionStrings>
    <add    name="MyAppContext"
          connectionString="metadata=
            res://OriginalProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null/LoadingModel.LoadingModel.csdl|
            res://OriginalProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null/LoadingModel.LoadingModel.ssdl|
            res://OriginalProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null/LoadingModel.LoadingModel.msl;
            provider=System.Data.SqlClient;
            provider connection string=&quot;data source=ThisIsADataSource;initial catalog=ThisIsADatabase;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework&quot;"
          providerName="System.Data.EntityClient" />
</connectionStrings>
The stack trace for the exception is as follows:
at System.Data.Entity.Core.Objects.ObjectContext..ctor(EntityConnection connection, Boolean isConnectionConstructor, ObjectQueryExecutionPlanFactory objectQueryExecutionPlanFactory, Translator translator, ColumnMapFactory columnMapFactory)
at System.Data.Entity.Core.Objects.ObjectContext..ctor(EntityConnection connection)
at System.Data.Entity.Internal.InternalConnection.CreateObjectContextFromConnectionModel()
at System.Data.Entity.Internal.LazyInternalContext.InitializeContext()
at System.Data.Entity.Internal.InternalContext.Initialize()
at System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType)
at System.Data.Entity.Internal.Linq.InternalSet1.Initialize()
at System.Data.Entity.Internal.Linq.InternalSet
1.GetEnumerator()
at System.Data.Entity.Infrastructure.DbQuery1.System.Collections.Generic.IEnumerable<TResult>.GetEnumerator()
at System.Collections.Generic.List
1..ctor(IEnumerable1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable
1 source)
at OriginalProject.LoadingModel.LoadingTable.GetDependencyOrder(Int32 issid, MyAppContext context) in c:\FILEPATH\OriginalProject\LoadingModel\Partials\LoadingTable.cs:line 83
Apr 7, 2014 at 9:09 AM
And here's my partial class, if that's of any interest for anyone.
namespace OriginalProject.LoadingModel
{
    public partial class MyAppContext : DbContext
    {
        public MyAppContext(DbConnection connection) 
        : base(connection, true)
        {
            this.Configuration.LazyLoadingEnabled = false;
        }
    }
}
Apr 7, 2014 at 11:15 AM
I got it working!
I'm not sure I'm doing it exactly as suggested, but it works, and I'm not making any changes to my actual database.

Okay, so I dug a bit deeper and tried different things to see if i could find a solution, which lead me to a couple of issues.
I came across Effort through this article:
http://www.codeproject.com/Articles/460175/Two-strategies-for-testing-Entity-Framework-Effort
The author is not in the same situation as me, as he's creating his own DbContext class, and uses that, and he uses DbConnectionFactory instead of EntityConnectionFactory (which I tried, and as you say in your tutorial, I got an UnintentionalCodeFirstException).
But what I was going to say about it was that I set up my test values as he does, that is I do it in the TestInitialize method, creating a new context in a using statement, and after that I set the _context variable that I want to use in the tests, creating a new MyAppContext.

The thing is that since i use true in the second parameter (contextOwnsConnection) in my MyAppContext constructor, the connection that I use will be disposed when the context is disposed. That is the reason I got an exception before, because I tried to create a context with a disposed connection. So I decided to try to change the contextOwnsConnection parameter to false, and then I didn't get the exception anymore. So that's the reason for the exception.

My problem still existed, though. I couldn't let my context get disposed, because then I lose the test values that I insterted, even when I called context.SaveChanges(). So instead of using the using statement in the TestInitialize method, I just created the context, filled it, and called SaveChanges() and used that context for the test methods.

Because I then don't try to recreate another context with the same connection, the contextOwnsConnection didn't need to be set to false, but should actually be set to true so that the connection is disposed with the context.

So now I have a few successfully running tests. Great. :)

If you have any comments on this, that would be nice. My only fault was trying to create multiple contexts with the same connection, which I was led to believe you could through the article...
May 5, 2014 at 11:20 PM
Sorry for replying so late.

Actually I suggest to use multiple context instances with the same connection object. In this case the contextOwnsConnection parameter should be indeed set to false. However in this case you have to handle the lifetime of the connection object externally. This blog post (and the one it refers) presents a technique to integrate Effort with complex applications and describes a way of lifetime handling. It uses ObjectContext, but the same techniques should work with DbContext too.