2

Closed

DbConfiguration.SetInitializer Reference Context Problem

description

I'm unable to use the SetInitializer method of EF6 DbConfiguration. Here's the problem I'm encountering.

I have one project for my model, HotelRoomsModel, which inherits DbContext.
I'm using Migrations so in the same project, I have a Configuration file.

In a second project I created a DbConfiguration class and one of the configuraitons is to set the database initializer for my model.

namespace DataLayer.DbConfigurations
{
public class CustomDbConfiguration : DbConfiguration
{
public CustomDbConfiguration()
{
  SetDefaultConnectionFactory(new LocalDbConnectionFactory("v11.0"));
  SetDatabaseInitializer(new MigrateDatabaseToLatestVersion
                                        <HotelRoomsModel, HotelModel.HotelMigrations.Configuration>());
 }
}
}

In order to specify the context, this project needs a reference to the model's project.

Now I need to "trigger" the configuration. One method as per your overview is to use an attribute in the DbContext. However, that would require the model project to have a reference to the DbConfiguration project which would create a circular reference.

So that's problem #1 because my understanding of the specs and the overview samples was that I should be able to do this.

The alternate suggestion is to specify the DbConfiguration in the app.config file.

<entityFramework codeConfigurationType="DataLayer.DbConfigurations.CustomDbConfiguration,DbConfigurations"/>

I have yet another project which is a console app. In the main method all I'm doing is initializing my model.

If I run without debugging, I get a stackoverflow exception.

If I debug I can see it hit the code as follows:

1) Instantiate HotelsRoomsModel class
2) Instantiate CustomDbConfiguration class
3) SetDefaultCOnnetionFactory in CustomDbConfiguraiton
4) SetDatabaseInitalizer in CustomerDbConfiguration
5) Then it seems to recursively instantiate this class over and over until it overflows.

I stopped it before it overflowed even then the inellitrace file I collected is over 16MB and too big to attach.

Can you easily reproduce it? Would you like me to attach a solution? Or am I doing something very obviously wrong that you can see in the description above?

file attachments

Closed Feb 27 at 11:30 PM by RoMiller
Verified by Mugdha

comments

ajcvickers wrote Nov 20, 2012 at 4:19 PM

"One method as per your overview is to use an attribute in the DbContext. However, that would require the model project to have a reference to the DbConfiguration project which would create a circular reference."

You can specify the DbConfiguration type using a string instead of the actual type. This will then not require a reference to the project that contains the context. Also, can I ask why use chose to not locate the DbConfiguration in the same assembly as the context?

Can you please provide a repro for the second problem.

jlerman wrote Nov 30, 2012 at 5:12 PM

Thanks Arthur. I've replied in email re a report. About the separate dbconfiguration...I have multiple contexts that live in separate projects. If I have a common configuration to share I want that in a separate project. And the specs suggested that this was supported so naturally I had to try it out! :)

jlerman wrote Dec 15, 2012 at 12:54 PM

thanks. I had also tried the string overload. I will go through all of my attempts again and then send you the project.

ajcvickers wrote Feb 18 at 11:21 PM

Pinged Julie again by email.

jlerman wrote Feb 19 at 1:47 AM

out of sight out of mind! Attached.

ajcvickers wrote Feb 19 at 5:47 PM

EnsureLoadedForContext is called from various places as soon as a context type is known to ensure that the correct DbConfiguration is found. However, sometimes the derived DbConfiguration itself can make use of a context type (such as when the Migrations initializer is used) in which case this would cause recursive calls into EnsureLoadedForContext resulting in stack overflow. The solution is to flag that the assembly has been visited at the start of the call instead of the end.

jlerman wrote Feb 19 at 6:31 PM

ahh okay so I wasn't doing it wrong? or was there a better way I should have set this up?

I'm also curious about the circular reference I ran into trying to set this up with attributes. Any ideas?

thanks

ajcvickers wrote Feb 20 at 6:02 PM

Update: Brice recognized that the previous iteration introduced a race condition which would have allowed an app to use configuration before it was properly configured. Second iteration changes EnsureLoadedForContext to only create the type rather than the instance such that the change that introduced the race condition is not now needed.

ajcvickers wrote Feb 20 at 6:39 PM

Commit: f344923ea335