I have a library for the data access layer where it uses Entity Framework, in the DbContext class I pass the connection string name DefaultConnection through the constructor, then I add this connection string to the app.config file for this library.
But when I update to the database I find the database is not created into this connection string server and catalogue?
Anybody please explain how migration and update database handle connection strings?
Your library can't access the app.config file in run time. Only executable components can (a web api, a console application, etc.). You have to define the connectionString value in the config file of the executable component that uses your library, not in the library's app.config file. The only scenario when the library's app.config file connection string can be used is when running Entity Framework commands in the Package Manager console (like add-migration and similar ones).
The recommended way to deal with connection strings is that the data layer library doesn't care at all about the responsibility of obtaining the connection string value. Instead, the client that uses the library should provide the connection string when instantiating the data layer classes. The responsibility of getting the value should be in that client component, using code like this to get the value to be passed to the data layer:
var connectionString = Configuration.GetConnectionString("MyConnectionString");
A common practice is to use a dependency injection component (like Autofac) so that the client injects the connection string as a parameter in the DbContext constructor, or in a property, after getting it from the configuration file (or possibly from other place).
There are also several approaches about what parts of your data layer you expose to the client components that use it: you can directly create instances of the DbContext, or use the Repository pattern, or the UnitOfWork pattern. The important concept here is that whenever your client component creates an instance of one of your data layer classes, it has to get the connection string value from wherever it is and pass it to the data layer component (via directly invoking the constructor and passing the connection string value as a parameter, or setting a property, or via your dependency injection component).
More info here and here.
Update: added some info about execution from Package Manager console:
To pass the connection string tothe Package Manager console you can do several things:
Add an explicit parameter ConnectionString to your console commands (the complete connection string, not only the name in the config file). This avoids the need to add the connection string to your library's config file.
Add an explicit parameter ConnectionStringName to your console commands. Define that connection string in the library app.config (but be careful and don't forget that it will only be used from the console, and that the one used in run time is the one in the executable component config file. This approach may lead to some mistakes).
Add a parameterless constructor to your DbContext with the connection string name hard-coded in the base constructor call, like this:
public MyDbContext() : base("DefaultConnection") { ... }
This will be the one that console manager will use. For real code execution use the other constructor with the parameter. Again, the connection string must be defined in the library's app.config file and this may lead to mistakes.
Also, console manager uses by default the configuration from the project selected as start project in your solution. If this project is not the database library it will not work like you want. To fix this you should set your solution as "Multiple start up projects", and select the database layer project in the console manager "Default project" drop down list (or pass a DefaultProject parameter with the data layer project name to your console commands).
Related
I'm building an API that needs to connect to a different database per request. Currently I'm using EF. These databases all have the same schema, therefore I can share a DbContext class. I have repositories to abstract persistence, and these are the ones using the DbContext objects.
Unity is handling dependency resolution, it is injecting my repositories with DbContext objects, and the repos on the controllers. Basically with zero configuration. I understand that probably I may need to create my own HttpRequestLifeCycle thing as suggested in this answer to make sure I have the same DbContext object through out the request.
Now, I would like to configure a ConnectionString to be used by Unity when creating DbContext objects to pass along to the repositories.
These ConnectionString will come from a repository (most likely a different fixed database), based on a parameter on my route. So, my intention is to have a delegating handler inspect the route, get the parameter, get the ConnectionString and tell Unity: "here, use this particular connection string when creating DbContext objects for my repositories during this request."
First, is my approach reasonable? Is this achievable?
How would this dynamic parameter configuration done?
Thanks in advance,
Yes, this is reasonable and achievable and frankly, easy.
Just approach this differently, instead of thinking how to inject connection strings, just register a factory for your db contexts. In the factory method, use the route information to read the connection string and return the context.
containe.Register<MyDbContext>( new InjectionFactory(
c => {
// this is the factory method
// the code will be executed upon each resolution
String routeInfo = GetTenantFromCurrentRoute();
String cs = GetCsFor( routeInfo );
return new MyDbContext( cs );
}, new PerHttpRequestLifetimeManager() )
I have a method where the DBContext is pass in (this is only POC code).
I then try to open another nested transaction, With this code
using (var cxt = new TestEntities(context.Database.Connection, false))
{
using (DbContextTransaction dbContextTransaction = cxt.Database.BeginTransaction())
{
The call to "BeginTransaction" gives this error:
An exception of type 'System.Data.Entity.Infrastructure.UnintentionalCodeFirstException' occurred in TestEF6.exe but was not handled in user code
Additional information: The context is being used in Code First mode with code that was generated from an EDMX file for either Database First or Model First development. This will not work correctly. To fix this problem do not remove the line of code that throws this exception. If you wish to use Database First or Model First, then make sure that the Entity Framework connection string is included in the app.config or web.config of the start-up project. If you are creating your own DbConnection, then make sure that it is an EntityConnection and not some other type of DbConnection, and that you pass it to one of the base DbContext constructors that take a DbConnection. To learn more about Code First, Database First, and Model First see the Entity Framework documentation here: http://go.microsoft.com/fwlink/?LinkId=394715
I have a Database First Model
Any clues?
Regards
GregJF
In Entity Framework 5 model first, there seem to be some breaking changes due to the way the class files are generated (No more code generation, but T4 templates)
2 examples:
The generated context file doesn't implement IDisposable anymore
There isn't a constructor which takes a connectionstring anymore
Are there more breaking changes? And what is the solution to them?
The default code generated from a model in Entity Framework 5 now inherits DbContext instead of ObjectContext.
This still implements IDisposable, but if you're getting an error from a line of code similar to this:
using (var mymodel = new MyModelContext()) { ... }
...complaining about not implementing IDisposable, then your problem is most likely that your model is defined in a separate assembly that references EF5 and you have not added an EF5 reference to your project.
As Ladislav Mrnka has already mentioned in his answer, if you want to pass a connection string to the constructor you have to create your own constructor manually to do this.
If you want to switch Entity Framework back to the older style of generated code, which will automatically generate the constructor you're looking for, then follow these steps:
Click on the designer surface of your EDMX file, and look at the properties window. Find a property called "Code Generation Strategy" and set this to "Default" instead of "None". This will tell Visual Studio to start creating the code for your object model in MyModel.Designer.cs in one big file, this time using ObjectContext instead of DbContext.
Delete the following sub files from below your EDMX file: MyModel.Context.tt, MyModel.tt. These are the auto generated files that you don't want anymore. If you don't delete them you'll get class naming conflicts because your objects will be created twice.
The generated context file doesn't implement IDisposable anymore
IDisposable is still implemented by the parent context type. The generated type is still disposable.
There isn't a constructor which takes a connectionstring anymore
It now uses convention to get connection string but you can add your own constructor either to template or to your partial class part of the context.
Are there more breaking changes? And what is the solution to them?
It is whole breaking change because it uses different API - DbContext API instead of ObjectContext API which means different types, different methods, POCO entities etc. If you want to get back to original code generation you have to delete those T4 templates and enable code generation as described in .Designer.cs file but the current recommended way is to use POCOs and DbContext API.
I was having the same issue with the using statement needing a type that extended IDisposable... Turns out that I forgot to reference System.Data.Entity in my project... Added the reference and it fixed the problem.
Just clean and build the project, don't forget to add the reference to your entity.
I am trying to use Entity Framework data migrations, as described in this post.
However, when I try to execute the Enable-Migrations step, I receive the following error in Package Manager Console:
The target context 'MyDataContext' is not constructible. Add a default constructor or provide an implementation of IDbContextFactory
So, I created a factory class that implements IDbContextFactory in the project that contains my DbContext class, but data migrations doesn't appear to recognize it.
Is there something that I should explicitly do to instruct data migrations to use this factory class?
I also hit this problem as i wrote my context to take a connection string name (and then used ninject to provide it).
The process you've gone through seems correct, here is a snippet of my class implementation if it's of any help:
public class MigrationsContextFactory : IDbContextFactory<MyContext>
{
public MyContext Create()
{
return new MyDBContext("connectionStringName");
}
}
That should be all you need.
Like #Soren pointed out, instead of using IDbContextFactory, not supported on some earlier EF Core releases (i.e. EF Core 2.1), we can implement IDesignTimeDbContextFactory<TContext>, which supports the missing ConnectionString parameter.
For a settings.json based aproach, which you can use with either of the referred interfaces, check #Arayn's sample which allows us to define "ConnectionStrings:DefaultConnection" value path
Update 1
According to #PaulWaldman's comment, on EF Core 5 support for IDbContextFactory was reintroduced. For further details, check his comment below.
For various reasons I would like to not store the connection string for my Entity Framework DB model in one of the various .config files. (I am using the latest and greatest DBContext API with the new Entity Framework version 4.1, .NET 4 and Visual Studio 2010 C#.) However, the code generation template for DBContext only creates a single parameterless constructor. (If I don't use the DBContext API, then my entity framework model has 7 different constructors to chose from, including the one I want.)
The only way I could figure out how to do this was to directly modify the code-generation template (context.tt file) to give me the constructor I want (example code below). This works, but it feels like I'm doing it "the hard way". What is the correct way to get a DBContext constructor that accepts a connection string?
public <#=Code.Escape(container)#>(string connectionString)
: base(connectionString)
{
<#
WriteLazyLoadingEnabled(container);
#>
}
One final note in case it might help somebody else. Although this method works, it took me a while to realize that the "connection string" is not strictly the DB connection string, but rather the special entity framework connection string which contains the DB connection string (just like what would be stored in the app.config file).
Your approach looks like the most correct way to do this. It's what the t4 templates were created for, and you're basically doing the same thing that the model-first templates do by default.
Another possibility would be to make the db context class be partial (if it isn't by default) and create another partial class file alongside it to add the constructor you want. But it seems likely that you'll want all of your t4-generated contexts to follow this pattern, so I think it's best to leverage the code generation to do this automatically the way you do in the question.