1

Background:

I have a Web API project and a Class Library project in the same solution that share the same Model classes. Both projects share the same database and both use DbContext to read/write data.

The Web API project is set up in the typical UnitOfWork pattern and works just fine.

The class project is a bit different. I specify the connection string in the constructor instead of the Web.config file:

class MyContext : DbContext
{
    public MyContext(string connectionString)
        : base()
    {
        // Do this to force me to use eager loading
        this.Configuration.LazyLoadingEnabled = false;
        // Init connection string
        this.Database.Connection.ConnectionString = connectionString;
        Database.SetInitializer <CFCalcContext> (null);
    }


    ... DbSets ...

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        ... modelBuilder details ...
    }
}

I use the Web API to call a function defined in the class library. When I attempt to query the database using the class library I get an error.

The Problem:

In the class library project I get a EntityCommandCompilationException with the inner exception as:

InnerException: System.Data.MappingException HResult=-2146232032 Message= (82,10) : error 3034: Problem in mapping fragments starting at lines 82, 90:Two entities with different keys are mapped to the same row. Ensure these two mapping fragments do not map two groups of entities with different keys to the same group of rows.

(82,10) : error 3034: Problem in mapping fragments starting at lines 82, 98:Two entities with different keys are mapped to the same row. Ensure these two mapping fragments do not map two groups of entities with different keys to the same group of rows.

(82,10) : error 3034: Problem in mapping fragments starting at lines 82, 106:Two rows with different primary keys are mapped to the same entity. Ensure these two mapping fragments do not map two groups of entities with identical keys to two overlapping groups of rows.

(82,10) : error 3034: Problem in mapping fragments starting at lines 82, 112:Two entities with different keys are mapped to the same row. Ensure these two mapping fragments do not map two groups of entities with different keys to two overlapping groups of rows.

(82,10) : error 3034: Problem in mapping fragments starting at lines 82, 118:Two entities with different keys are mapped to the same row. Ensure these two mapping fragments do not map two groups of entities with different keys to two overlapping groups of rows.

(90,10) : error 3034: Problem in mapping fragments starting at lines 90, 98:Two entities with different keys are mapped to the same row. Ensure these two mapping fragments do not map two groups of entities with different keys to the same group of rows.

Also, when I right click the derived DbContext class (in the class library) and use Entity Framework Power Tools to "View Entity Data Model" I get the error: "A constructible type deriving from DbContext could not be found in the selected file." This works just fine in the Web API project.

Why would two DbContexts that connect to the same database and are configured basically the same perform differently? I must be missing a configuration step, but I don't know which.

Thanks for the help!

brudert
  • 537
  • 8
  • 21
  • Could this be a problem with having two DbContext's running at once (one in the Web API and one in the dll)? http://entityframework.codeplex.com/wikipage?title=Multi-tenant%20Migrations – brudert Apr 05 '13 at 22:19

1 Answers1

0

A lot going on here. Firstly, if you're manually setting the connection string you should be setting it in the call to the base constructor:

public MyContext(string connectionString)
    : base(connectionString)

Secondly though, you should really be putting that in Web.Config - if the name is the issue, you can give it a different name like:

public MyContext()
    : base("Whatever name I used in Web.Config")

Third this is probably just wrong:

Database.SetInitializer <CFCalcContext> (null);

The documentation for Database.SetInitializer states:

Gets or sets the database initialization strategy. The database initialization strategy is called when DbContext instance is initialized from a DbCompiledModel.

In other words setting it to null is likely to make your DbContext explode as soon as it tries to do anything - I suspect that's what's happening to you here.

Chris Moschini
  • 36,764
  • 19
  • 160
  • 190
  • Hi Chris, thanks for the answer. I'm manually setting the connection string to allow whomever wishes to use the dll down the road to use whichever database they want. I'll use your advice to set the connection string using the base constructor. [Edit: actually, that didn't work] Thanks! I used Database.SetInitializer<>(null) to prevent the bug when using existing databases (see: http://stackoverflow.com/questions/3552000/entity-framework-code-only-error-the-model-backing-the-context-has-changed-sinc) I tried your advice but it did not solve my problem. Thanks though! – brudert Apr 05 '13 at 17:40
  • @brudert Are you using EF Code First in both DbContexts talking to this database? If so you shouldn't be using SetInitializer(null) - you should be using EF Migrations to sync the model with the database like >update-database -verbose. What didn't work with setting the connection string from the base constructor? I have several projects that do just that, so if it isn't working for you - something else is broken. – Chris Moschini Apr 05 '13 at 18:20
  • I'm using EF Migrations for my Web API project, but for the class project (dll) I only read the database, not write to it. Is there a way to sync a read-only project to an existing database that is managed by a different project? This is becoming a separate question, however. – brudert Apr 05 '13 at 20:56
  • When using your suggested code to set the connection string using the base constructor then calling `context.Database.Connection.Exists()` I get "Evaluation requires a thread to run temporarily...", but when using my code I get "true". Also, `context.Database.Connection.ConnectionString` returns "Evaluation requires a thread..." but with my code it returns the connection string. I'm sure I'm doing something wrong. – brudert Apr 05 '13 at 21:16
  • What do the 2 projects share? Is there a common third project with all of the Models in it? Does the shared project contain anything else, like the DbContext, Migrations and MigrationConfiguration? – Chris Moschini Apr 05 '13 at 21:37
  • First of all, thanks for sticking with me here :) Yes, there is a third project that contains the models. The Migrations and MigrationConfigurations are in the Web API project. Note that I enabled migrations in the Class Project (so had a Migrations folder in both projects) without any luck. – brudert Apr 05 '13 at 21:45
  • 1
    I think I see the core issue here - the DbContext class, MigrationsConfiguration class, and Migrations can be in exactly one project, which must be shared by all projects using EF to talk to that DB. In addition to the code not supporting 2 DbContext classes, it also wouldn't make sense, since you really want only one record of manual migrations - it would be strange to have to keep copying them between projects. – Chris Moschini Apr 05 '13 at 22:08
  • I was hoping to later spin the dll project off and allow it to be used independently from the Web API. For now though, since I cannot use 2 DbContext classes in one solution, does that mean I need to use some other way to consume the database? Should I do raw SQL commands? Yikes! – brudert Apr 05 '13 at 22:23
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/27673/discussion-between-chris-moschini-and-brudert) – Chris Moschini Apr 05 '13 at 23:19