Entity Framework Database Initialization Seed is not working - c#

I'm using EF Code-First with Identity and I have customized ApplicationUser so changed my DbContext and Initializer a little bit.
Having following classes:
public class MyDbContext : IdentityDbContext
{
public MyDbContext() : base("DefaultConnection")
{
Database.SetInitializer(new MyDbInitializer());
Database.Initialize(false);
}
}
public class MyDbInitializer : CreateDatabaseIfNotExists<ApplicationDbContext>
{
protected override void Seed(ApplicationDbContext context)
{
// data initialization code here
}
}
In my unit test I create MyDbContext so I expect the Seed method gets called. Note that I don't have migration and this issue is happening in the first run.
The Seed method was being called before I inherit MyDbContext IdentityDbContext instead of DbContext. After inheriting from IdentityDbContext the Seed method is firing anymore.
ApplicationDbContext and IdentityDbContext are coming from Identity framework
Thanks for help.

Related

How to make edmx DbContext inherit from IdentityDbContext

Im trying to integrate asp.net identity to my existing project
i'm working with Database first, and using edmx to generate the models and context class,
Now in the Context class that is generated with edmx, i need to change the inheritance from DbContext TO IdentityDbContext but when i refresh the edmx all changes gets removed from the Context class,
So my question is how can i inherit from IdentityDbContext when using edmx
Change these
public ConfigurationContext(DbContextOptions<ConfigurationContext> options):base(options)
public IdentityDbContext (DbContextOptions<IdentityDbContext> options):base(options)
to this
public ConfigurationContext(DbContextOptions options):base(options)
public IdentityDbContext (DbContextOptions options):base(options)
Example
public class QueryContext : DbContext
{
public QueryContext(DbContextOptions options): base(options)
{
}
}

EF Code-First from existing db add models into existing DbContext

So maybe this is a stupid question, because I know that when creating a Code-first model from an existing database, Visual Studio will create a new ADO.NET Entity Data Model, and add the models in a new DbContext.
I am using Microsoft Identity in my project, hence there is already a ApplicationDbContext (IdentityDbContext). I think just having all my models in a single DbContext would be easier to handle. I am generating my code-first models from an existing database.
But Is there a way such that the generated models add up into the already existing DbContext (In this case, the IdentityDbContext?)
I have like, many models, so currently I am compelled to add each of them into existing ApplicationDbContext manually, and remove from the created DbContext.
As far as I remember there is no way to add the generated models objects to the existing DbContext automatically. You need to add them manually.
public partial class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("name=DefaultConnection")
{
}
//Add your Model objects here, You can copy them from automatically generated DbContext
public virtual DbSet<ModelObjectName> PropertyName { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//Copy the modelBuilder configuration here from automatically generated DbContext here
base.OnModelCreating(modelBuilder);
}
}
Here's an alternative that works:
Mark your ApplicationDbContext class as partial:
public partial class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext() : base("DefaultConnection")
{
//unchanged
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//unchanged
}
}
Do the same with your custom Data model class, and remove the inheritance from DbContext. Also, remove constructor form it and change the OnModelCreating into a regular private method with some different name. Keep the rest unchanged.
public partial class MyDataModels
{
//unchanged
private void OnModelCreating2(DbModelBuilder modelBuilder)
{
//unchanged
}
}
Refactor (Ctrl + R + R : default shortcut) name of your Data model class, and change it to ApplicationDbContext. Visual Studio might give you a conflict warning during refactoring, ignore that and refactor. Finally, call OnModelCreating2() from OnModelCreating() method of ApplicationDbContext class.
public partial class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext() : base("DefaultConnection")
{
//unchanged
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//unchanged
OnModelCreating2(modelBuilder);
}
}
Another nice approach suggested by #DevilSuichiro is to simply inherit your Data model class from ApplicationDbContext.
Cheers!

Consider using IDbContextFactory to override the initialization of the DbContext at design-time

On an ASP.NET Core 1.0.1 project, using Entity Framework Core and ASP.NET Identity, I have the following context:
public class Context : IdentityDbContext<User, Role, Int32, UserClaim, UserRole, UserLogin, RoleClaim, UserToken> {
public Context(DbContextOptions options) : base(options) { }
protected override void OnModelCreating(ModelBuilder builder) {
base.OnModelCreating(builder);
}
}
And the following entities:
public class User : IdentityUser<Int32, UserClaim, UserRole, UserLogin> { }
public class Role : IdentityRole<Int32, UserRole, RoleClaim> { }
public class RoleClaim : IdentityRoleClaim<Int32> { }
public class UserClaim : IdentityUserClaim<Int32> { }
public class UserLogin : IdentityUserLogin<Int32> { }
public class UserRole : IdentityUserRole<Int32> { }
public class UserToken : IdentityUserToken<Int32> { }
On Startup I have the following:
services.AddDbContext<Context>(x => x.UseSqlServer(connectionString, y => y.MigrationsHistoryTable("__Migrations")));
services
.AddIdentity<User, Role>()
.AddEntityFrameworkStores<Context, Int32>()
.AddDefaultTokenProviders();
When I run dotnet ef migrations add "FirstMigration" I get the following error:
An error occurred while calling method 'ConfigureServices' on startup
class 'WebProject.Startup'. Consider using IDbContextFactory to
override the initialization of the DbContext at design-time. Error:
GenericArguments[0], 'WebProject.User', on
'Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore`4[TUser,TRole,TContext,TKey]'
violates the constraint of type 'TUser'.
How to solve this problem?
I apologise for posting a partial answer but it will be usefull for many...
An error occurred while calling method 'ConfigureServices' on startup class
Your method Startup.ConfigureServices(...) is being called and it is throwing an exception. The exception probably happens because when running dotnet ef the application entry point is not Program.Main() as usual.
Try
dotnet ef migrations add "FirstMigration" --verbose
That will print the error message and you will be able to better understand the issue.

DBContext overwrites previous migration

I currently have two DbContexts, ApplicationDbContext and CompanyDBContext. However the problem is that when I run my MVC web application only the CompanyDBContext gets reflected on the database and I see none of the implementation made in ApplicationDbContext being shown in the database. Both my contexts use the same connection string. The ApplicationDbContext was auto-generated when I created my MVC application as I had selected Individual accounts
Currently the ApplicationDbContext looks like this
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DevConnection", throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Ignore<CompanyDetails>();
}
}
and here is my CompanyDbContext
public class CompanyDBContext : DbContext
{
public CompanyDBContext() : base("DevConnection")
{
}
public DbSet<CompanyDetails> companies { get; set; }
}
I would delete the migrations you have now if you dont need them then use the command below to enable them separately by specifying their names and directories, so they are created separately.
enable-migrations -ContextTypeName MyCoolContext -MigrationsDirectory MyCoolMigrations
http://www.mortenanderson.net/code-first-migrations-for-entity-framework
I was curious, so I looked around, and it seems like the solution for migrations and multiple DbContexts is to have a single DbContext that serves as a complete representation of the database through which initialization and migration is handled, and disable database initialization in the constructor of all other DbContext classes.
You could do this through a combination of Database.SetInitializer and an explicit call to DbContext.Database.Initialize()
Sources
Entity Framework: One Database, Multiple DbContexts. Is this a bad idea?
Shrink EF Models with DDD Bounded Contexts
It's seems like only one dbContext can be updated at a moment. You must Enable-Migration , Add-Migration and Update-Database for each dbContext. This is the way i do it. But my dbContext were in different projects, so may be it can be the same for you! Update separately didn't overwrite my database. It works for me !
In think the problem you have, it that your database tables / migrations are not separated.
In EF6 if you work with more than one context, I recommend to specify the name for the default schema in the OnModelCreating method of you DbContext derived class (where the Fluent-API configuration is).
public partial class ApplicationDbContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.HasDefaultSchema("Application");
// Fluent API configuration
}
}
public partial class CompanyDBContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.HasDefaultSchema("Company");
// Fluent API configuration
}
}
This example will use "Application" and "Company" as prefixes for your database tables (instead of "dbo") in your (single) database.
More importantly it will also prefix the __MigrationHistory table(s), e.g. Application.__MigrationHistory and Company.__MigrationHistory.
So you can have more than one __MigrationHistory table in a single database, one for each context.
So the changes you make for one context will not mess with the other.
When adding the migration, specify the fully qualified name of your configuration class (derived from DbMigrationsConfiguration) as parameter in the add-migration command:
add-migration NAME_OF_MIGRATION -ConfigurationTypeName FULLY_QUALIFIED_NAME_OF_CONFIGURATION_CLASS
e.g.
add-migration NAME_OF_MIGRATION -ConfigurationTypeName ApplicationConfiguration
if ApplicationConfiguration is the name of your configuration class.
In such a scenario you might also want to work with different "Migration" folders in you project. You can set up your DbMigrationsConfiguration derived class accordingly using the MigrationsDirectory property:
internal sealed class ApplicationConfiguration: DbMigrationsConfiguration<ApplicationDbContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
MigrationsDirectory = #"Migrations\Application";
}
}
internal sealed class CompanyConfiguration : DbMigrationsConfiguration<CompanyDBContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
MigrationsDirectory = #"Migrations\Company";
}
}

DbSet outside of DbContext class

My project has couple of Areas which each one of them has their own entities and I'm trying to keep everything isolate in that area... (lets call those areas = plugins)
DbContext
public class PortalDbContext : DbContext, IUnitOfWork
{
public new IDbSet<TEntity> Set<TEntity>() where TEntity : class
{
return base.Set<TEntity>();
}
}
IUnitOfWork
public interface IUnitOfWork
{
int SaveChanges();
IDbSet<TEntity> Set<TEntity>() where TEntity : class;
}
Service.cs
public class PageService : IPage
{
public readonly IUnitOfWork _uow;
public readonly IDbSet<Pages> _page;
public PageService(IUnitOfWork uow)
{
_uow = uow;
_page = uow.Set<Pages>();
}
}
Finally When I try:
public void AddPage(PageModel m)
{
_page.Add(m);
}
I get this error:
The entity type Pages is not part of the model for the current context
this means uow.Set<Pages>(); doesn't worked properly.
is it possible to DbSet out of DbContext class is ASP.Net MVC code first?
Actually, this error message
The entity type Pages is not part of the model for the current context
means, that the type PageModel was not configured as an entity type for the PortalDbContext context instance. You should either follow conventions to build your model (see this page, "Type Discovery" paragraph), or build model manually, using fluent API.
The second scenario fits dynamic models for plugin-based applications, because you can discover models types, using custom algorithm, and call DbModelBuilder methods to "assembly" model.
is it possible to DbSet out of DbContext class is ASP.Net MVC code first?
In short, you can't use DbSet<TEntity> without DbContext.
Consider DbSet as a part of context (AFAIK, DbSet holds a reference to DbContext, which was used to create DbSet).
Since ASP .NET is all about stateless, usual approach is to create DbContext instance (or its unit-of-work-like wrapper), perform an action, dispose the context, and throw it away. Holding references to DbContext/DbSet as a state in web applications at least useless.

Categories

Resources