I stumbled uppon the same problem as described in this question. In addition, i didn't want to loose the __migrationHistory table from the database.
I tried it with the suggested Solution of using one "super" context which contains all DbSet<>s and using the normal Contexts, but i got a error. ("Model backing DbContext has been changed")
This is easily avoidable if you just kill the __migrationHistory table from the SQL server, but as i said, i want to keep the history.
I found a simple and easy solution, see my answer below.
First, you have to create a "Super" Context for the Migrations Configuration.
MySuperContext : DbContext
{
// All DbSet<> s from your different contexts have to be referenced here once, you will only use this class for the migrations.
public MySuperContext() : base("YourConnectionString")
{
System.Data.Entity.Database.SetInitializer(new MigrateDatabaseToLatestVersion<MySuperContext, MyMigrationsConfiguration>());
}
}
Then just create the following class:
public class NoDatabaseInitializer<T> : IDatabaseInitializer<T> where T: DbContext
{
public void InitializeDatabase(T context)
{
// Do nothing, thats the sense of it!
}
}
now, in every small Context you have, add this to the constructor:
class MyUserContext : DbContext
{
public MyUserContext : base("MyConnectionString") // Can be a user context, etc
{
System.Data.Entity.Database.SetInitializer(new NoDatabaseInitializer<MyContext>());
}
}
now you won't get this error any more,
plus, you will have your migration-History,
and you will use multiple Contexts on one Database.
EF6 supports multiple DbContexts per database: http://entityframework.codeplex.com/wikipage?title=Multi-tenant%20Migrations
Related
I'm using the code first pattern to creating DB. I already have a DbContext/DB setup. Now I decided to add auth support to it using Identity.EntityFrameworkCore.
I've created another DbContext to have the identity related tables like below :
public class AccountDbContext:IdentityDbContext
{
public AccountDbContext(DbContextOptions<AccountDbContext> options) : base(options)
{
}
}
I've added the above DbContext in startup.cs as below :
services.AddDbContext<AccountDbContext>(o => o.UseSqlServer(Configuration.GetConnectionString("TESTDB")));
And finally :
dbContext.Database.EnsureCreated();
But since TESTDB is already associated with an existing db context, its already created. So I guess the function call - EnsureCreated() would do nothing and simply return.
My questions:
Is there any way to avoid creating a duplicate context for IdentityContext and somehow add it to my existing DB Context ?
If I do go about a separate DbContext like above (but using the same existing DB) how to ensure the Identity/roles tables are auto created ?
You can avoid to create two context by extending the AccountDbContext in your default DbContext.
public class YourDbContext : AccountDbContext
{
}
OK, found a solution. I can directly inherit the IdentityDbContext instead of DbContext (since IdentityDbContext extends DbContext anyway). Migrations can be added as usual.
I have two DbContext in my Project : ApplicationDbContext for ApplicationUser model (inherited from ASP.NET Identity IdentityUser class) and EFDbContext for all other models.
They use one database.
I created two database initializers for each of context:
public class ApplicationDbInitializer :
DropCreateDatabaseIfModelChanges<ApplicationDbContext>
{
protected override void Seed(ApplicationDbContext context)
{
// add Admin role and user
... code here
//
base.Seed(context);
}
}
And
public class EFDbInitializer : DropCreateDatabaseAlways<EFDbContext>
{
protected override void Seed(EFDbContext context)
{
}
}
The problem:
I get such error in App
An exception of type 'System.Data.SqlClient.SqlException' occurred in
EntityFramework.dll but was not handled in user code
Additional information: Cannot drop database "DatabaseName" because
it is currently in use.
I think it tries re-create database using one context initializer but database is in using by another context.
How to deal with such error?
Most of the times, using multiple db-contexts for the same database is considered as a bad practice. But if you really need this, I am quoting the great answer by Ladislav Mrnka from here:
The problem is when you want to use code first to create your database - only single context in your application can do that. The trick for this is usually one additional context containing all your entities which is used only for database creation. Your real application contexts containing only subsets of your entities must have database initializer set to null.
I have an application which uses EntityFramework edmx models and i want to be able to use the same dbContext for my Identity classes and the entity classes. Someone has raised a Similar Query but i am unable to get them to be compatible.
ive changed the class definition in the EF context class as below
public partial class MyDbContext : IdentityDbContext<AspNetUser>
{
}
and my identity user as
public partial class AspNetUser : IdentityUser
{
}
but i get an error when i try to login or register
The entity type AspNetUser is not part of the model for the current
context
The solution I came up with recently is to use single context for both ASP.NET identity data and your business entities:
public class DatabaseContext : IdentityDbContext<UserInfo>
{
public virtual DbSet<Comment> Comments { get; set; } // Your business entities
public DatabaseContext()
: base("name=DatabaseContext")
{
}
}
Notice that the DatabaseContext inherits from the IdentityDbContext.
There are some trade-offs with this approach: for example, your data access layer should reference Microsoft.AspNet.Identity.Core and Microsoft.AspNet.Identity.EntityFramework; however, having a single database context in your project makes things much easier if you are using dependency injection or Entity Framework migrations.
I recommend using those dbContext separate, due to async nature of how identity works. You want to have absolute control over your application context.
For that reason I usually inject the identity dbContext by using the same connection from the application context, but there are two separate instances.
Also if you ever wanted to have your application dbContext anything other than code first it will not be possible to merge with the identity dbContext.
BACKGROUND:
Our core framework loads all entity framework mappings from itself, the main application and any modules we have installed by using an interface (below):
public interface IEntityTypeConfiguration : IDependency
{
}
and we have a DbContext in our core framework like this, which loads all the mappings:
public class DefaultDbContext : DbContextBase
{
private readonly Lazy<IEnumerable<IEntityTypeConfiguration>> configurations;
public DefaultDbContext(Lazy<IEnumerable<IEntityTypeConfiguration>> configurations)
: base()
{
this.configurations = configurations;
Configuration.ProxyCreationEnabled = false;
}
public DefaultDbContext(string connectionString, Lazy<IEnumerable<IEntityTypeConfiguration>> configurations)
: base(connectionString)
{
this.configurations = configurations;
Configuration.ProxyCreationEnabled = false;
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
foreach (dynamic typeConfiguration in configurations.Value)
{
modelBuilder.Configurations.Add(typeConfiguration);
}
Database.SetInitializer(new CreateTablesIfNotExist<DefaultDbContext>());
}
}
So this way we have a single DbContext for everything.
PROBLEM:
We've run into an issue whereby when we dynamically add new modules (which have their own mappings), then EF does not load those mappings ever, even when we are sure that a new instance of DefaultDbContext has been created. So, it must be that EF is cacheing the mappings somewhere. Is there some way to clear the cache?
FINAL NOTE:
As you may have guessed, we are using an IoC, namely Autofac. If you need any further info, just ask.
Any ideas, anyone?
The model is cached for performance reasons.
The following excerpt explains what is going on
Model Caching
There is some cost involved in discovering the model, processing Data Annotations and applying fluent API configuration. To avoid incurring this cost every time a derived DbContext is instantiated the model is cached during the first initialization. The cached model is then re-used each time the same derived context is constructed in the same AppDomain.
This text also mentions a property called CacheForContextType but this didn't make it into the final release of EF5.
This second link provides a glimmer of hope but again is dated before the final release of EF5
We removed CacheForContextType in CTP5, we originally intended it to be used when folks wanted to use the same context in the same AppDomain with different models. The issue is that it would create the model on every initialization and didn't allow any way to cache a series of models and choose which one to use during each initialization. Model creation is expensive so we wanted to promote a better pattern.
The pattern we recommend is to externally create a ModelBuilder -> DbDatabaseMapping -> DbModel for each model you want to use. The DbModel should be cached and used to create context instances. The ModelBuilder -> DbModel workflow is a little messy and the class names aren't great, they will be tidied up for RTM.
Personally I think you're going to have to find a way of knowing all of your models up front ...
Solved! We found this constructor on the DbContext class:
public DbContext(string nameOrConnectionString, DbCompiledModel model);
I can't share all of the code here, but basically we're creating a new DbCompiledModel and passing that in whenever necessary.
We're using Database first approach with EntityFramework.
We've several customers, and when we deploy new product version, we're now applying DB schema changes "manually" with tools like SQL Compare.
Is there a way how EF Migrations could help to apply changes to customers DB automatically?
As far as I know, EF Migrations is a product targeted at CodeFirst and doesn't support Database First operations.
CodeFirst assumes that you will never make any changes manually to the database. All the changes to the database will go through the code first migrations.
I think there is! You need to continue your way through the code first.
To do this, Suppose that you have the following DbContext that EF Db first created for you:
public class MyDbContext : DbContext
{
public MyDbContext()
: base("Name=DefaultConnection")
{
}
// DbSets ...
}
change that to the following to start using code first and all magic tools of it (migration, etc.):
public class MyDbContext : DbContext
{
public MyDbContext()
: base("YourDbFileName")
{
}
// DbSets ...
}
It causes that EF creates a new connection string using SQL Express on your local machine in your web.config file with the name YourDbFileName, something just like the early DefaultConnection Db first created.
All you may need to continue your way, is that edit the YourDbFileName ConStr according to your server and other options.
More info here and here.
Starting Entity Framework 4.1 you can do Code First Migrations with an existing database.
So first you have the database, create the model, enable migrations.
The most important thing to remember that you should run Enable-Migrations before you do any changes to the schema since it should be in sync between your db and code.
Just look for your DbContext child object and look for this method:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
If you comment this:
throw new UnintentionalCodeFirstException();
then the exception would not be thrown on migration operation. As you might imagine, the migration look for this part to know what are the configurations for each entity with what table or tables.
Sorry if I didn't go with more details, if you wish more, I'll be happy to edit this and make it better!