Entity Framework Code First : Two DbContext and one database initializers - c#

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.

Related

How to update existing DB with Identity users and roles in .net core 2.1?

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.

purpose of Database.SetInitializer<ArContext>(null) inside of repository?

I am using entity framework and in my context inheriting from DbContext.
public class MyContext : DbContext, IMyContext
{
static MyContext()
{
Database.SetInitializer<MyContext>(null);
}
//other stuff
}
What is the purpose of this line?
Database.SetInitializer<ArContext>(null)
You can turn off the DB initializer of your application. On the production environment where you don't want to lose the existing data.In such scenario you can turn off the initializer, as shown below.
public MyContext()
{
Database.SetInitializer<MyContext>(null);//Disable initializer
}
There are four different database initialization strategies:
CreateDatabaseIfNotExists: This is default initializer. As the name
suggests, it will create the database if none exists as per the
configuration. However, if you change the model class and then run
the application with this initializer, then it will throw an
exception.
DropCreateDatabaseIfModelChanges: This initializer drops an existing
database and creates a new database, if your model classes (entity
classes) have been changed. So you don't have to worry about
maintaining your database schema, when your model classes change.
DropCreateDatabaseAlways: As the name suggests, this initializer
drops an existing database every time you run the application,
irrespective of whether your model classes have changed or not. This
will be useful, when you want fresh database, every time you run the
application, like while you are developing the application.
Custom DB Initializer: You can also create your own custom
initializer, if any of the above doesn't satisfy your requirements
or you want to do some other process that initializes the database
using the above initializer.
Reference : Database Initialization Strategies
The default database initializer in Entity Framework Code First is CreateDatabaseIfNotExists. As its name indicates, if the database does not exist it'll create it.
This behavior is good during development but when you go to production maybe you won't want to auto create your database.
If you want to disable the initializers you use the line you showed, so now you have full control over how the database will be created and evolve in time.
Other initializers:
DropCreateDatabaseIfModelChanges.
DropCreateDatabaseAlways
Custom DB Initializer
Check this to know more.

Why do I have 2 Data context classes when creating a controller in EF

I added a database to my project, then I want to add a controller.
When the Add Controller window pops up, I am asked to choose Data context class.
Surprisingly, I found that there are 2 context classes:
One is called: my_database_name_dbEntities(projectname)
Another one is called:
ApplicationDbContext(projectname.Models)
which is what I created when I added the Entity Framework object which connects to my database.
I am confused about
which one to use
what are the differences
Here is the screenshot
Update
I tried both of them and here is what I have got:
If I choose the databasename_dbEntities, VS generates views and controller perfectly with no problems.
If I choose ApplicationDbContext, VS throws an error:
Error
There was an error running the selected code generator:
'Unable to retrieve metadata for 'lrc.Event'. One or more validation
errors were detected during model generation:
AspNetUserLogin: : EntityType 'AspNetUserLogin' has no key defined.
Define the key for this EntityType.
AspNetUserLogins: EntityType: EntitySet 'AspNetUserLogins' is based on
type 'AspNetUserLogin' that has no keys defined.
'
Update
Now, I changed the super class from DbContext to IdentityDbContext for the projectname_dbEntities.
So it looks like this now:
public partial class projectname_dbEntities : IdentityDbContext<ApplicationUser>
{
public projectname_dbEntities()
: base("projectname_dbEntities", throwIfV1Schema: false)
//: base("name=projectname_dbEntities")
{
}
public static projectname_dbEntities Create()
{
return new projectname_dbEntities();
}
.....
}
I wonder :
what are the advantages of using the the derived class from IdentityDbContext over the DbContext?
Out of the box, when you create an ASP.NET MVC 5 project using the default template in Visual Studio 2013, you get a basic, ready-to-run website with the elementary Identity and Account management classes already in place.
There is a class ApplicationDbContext. This is the Entity Framework context used to manage interaction between your application and the database where your Account data is persisted (which may, or may not be the same database that will be used by the rest of our application) and this class inherits from IdentityDbContext.
IdentityDbContext is basically a regular DbContext with two DbSets. One for the Users and one for the Roles.
If you don't want use ASP.NET Identity, you can ignore it or mix it into your own DbContext class.

using same dbContext for Identity and other db entities

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.

Multiple DbContexts on one DB with Code First Migrations

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

Categories