0

I have an application that, I have now realised, stupidly has two separate DBcontexts and they need to be merged in order to allow for relationships between application entities and the ApplicationUser entity.

Along the development of the application I believe a reference to the applicationUser within other classes has created tables for the ApplicationUser entity on my DBcontext, whilst on a different connection string and context exists the tables for AspUserIdentity ect.

I have tried to remove the original context and merge the two contexts but when trying to create the migration it wants to rename all the existing ApplicationUser tables in my current context to AspUserIdentity ect (see below)

How can I successfully merge the contexts or is there another solution?

I'm not really sure what to post but i will try to post what i feel is relevant and then if anyone needs further information feel free to request it.

This is all code from after the attempted merge. (using the guide in one of the answer to this question : Merge MyDbContext to Asp.net IdentityDbContext)

My context has the following tables: ApplicationUsers IdentityRoles IdentityUserClaims IdentityUserLogins IdentityUserRoles

The original Context has the following tables and the migration is trying to rename the above tables to match these: AspNetRoles AspNetUserClaims AspNetUserLogins AspNetUserRoles AspNetUsers

My Context: (The Commented Modelbuilder statements were causing multiplicity errors )

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

using System.Data.Entity;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Configuration;
using System.Web.Mvc;
using Microsoft.AspNet.Identity.EntityFramework;
using System.Data.Entity.ModelConfiguration.Conventions;
using eCommSite.Models;
using System.Data.Entity.Infrastructure;

namespace eCommSite.Areas.Admin.Models
{
    public class TheDBContext : IdentityDbContext 
    {

        public TheDBContext()
                : base(ConfigurationManager.ConnectionStrings["DataDBString"].ConnectionString)
            {
                var objectContext = (this as IObjectContextAdapter).ObjectContext;

                // Sets the command timeout for all the commands
                objectContext.CommandTimeout = 360;
            }
        public DbSet<ProductBase> ProductBases { get; set; }
        public DbSet<Address> Addresses { get; set; }
        public DbSet<PromotionImage> PromotionImages { get; set; }
        public DbSet<Image> Images { get; set; }
        public DbSet<ImageCollection> ImageCollections { get; set; }
        public DbSet<Order> Orders { get; set; }
        public DbSet<OrderLine> OrderLines { get; set; }
        public DbSet<ProductOption> ProductOptions { get; set; }
        public DbSet<ProductOptionType> ProductOptionTypes { get; set; }
        public DbSet<ProductType> ProductTypes { get; set; }
        public DbSet<FilterValueEntry> FilterValueEntries { get; set; }
        public DbSet<FilterType> FilterTypesDB { get; set; }
        public DbSet<CardBaseSummary> CardBaseSummarys { get; set; }
        public DbSet<ProductBaseSummary> ProductBaseSummaries { get; set; }
        public DbSet<Category> Categories { get; set; }
        public DbSet<Brand> Brands { get; set; }
        public DbSet<MMHPriceEntry> MMHPriceEntries { get; set; }
        public DbSet<Legality> Legalities { get; set; }
        public DbSet<ForeignName> ForeignNames { get; set; }
        public DbSet<SKUStockQuantity> SKUStockQuantities { get; set; }
        public DbSet<Location> Locations { get; set; }
        public DbSet<Cart> Carts { get; set; }
        public DbSet<StockCollection> StockCollections { get; set; }

        public static TheDBContext Create()
        {
            return new TheDBContext();
        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();
            modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();


          //  modelBuilder.Entity<IdentityUserLogin>().HasKey<string>(l => l.UserId);
          //  modelBuilder.Entity<IdentityRole>().HasKey<string>(r => r.Id);
         //   modelBuilder.Entity<IdentityUserRole>().HasKey(r => new { r.RoleId, r.UserId });

        }

        public System.Data.Entity.DbSet<eCommSite.Areas.Admin.Models.ApplicationUser> ApplicationUsers { get; set; }

        public System.Data.Entity.DbSet<eCommSite.Areas.Admin.Models.ProductRelation> ProductRelations { get; set; }

        public System.Data.Entity.DbSet<eCommSite.Areas.Admin.Models.MTG_Cards> MTG_Cards { get; set; }

        public System.Data.Entity.DbSet<eCommSite.Areas.Admin.Models.MTG_Set> MTG_Set { get; set; }

        public System.Data.Entity.DbSet<eCommSite.Areas.Admin.Models.ProductOptionValue> ProductOptionValues { get; set; }

        public System.Data.Entity.DbSet<eCommSite.Areas.Admin.Models.SKU> SKUs { get; set; }

        public System.Data.Entity.DbSet<eCommSite.Areas.Admin.Models.MMHsetToJsonSetReference> MMHsetToJsonSetReferences { get; set; }

    }
}

The Migration:

namespace eCommSite.Migrations
{
    using System;
    using System.Data.Entity.Migrations;

    public partial class MergeMigration : DbMigration
    {
        public override void Up()
        {
            RenameTable(name: "dbo.ApplicationUsers", newName: "AspNetUsers");
            RenameTable(name: "dbo.IdentityUserClaims", newName: "AspNetUserClaims");
            RenameTable(name: "dbo.IdentityUserLogins", newName: "AspNetUserLogins");
            RenameTable(name: "dbo.IdentityUserRoles", newName: "AspNetUserRoles");
            RenameTable(name: "dbo.IdentityRoles", newName: "AspNetRoles");
            DropIndex("dbo.AspNetUserClaims", new[] { "ApplicationUser_Id" });
            DropIndex("dbo.AspNetUserLogins", new[] { "ApplicationUser_Id" });
            DropIndex("dbo.AspNetUserRoles", new[] { "ApplicationUser_Id" });
            DropIndex("dbo.AspNetUserRoles", new[] { "IdentityRole_Id" });
            DropColumn("dbo.AspNetUserClaims", "UserId");
            DropColumn("dbo.AspNetUserLogins", "UserId");
            DropColumn("dbo.AspNetUserRoles", "UserId");
            DropColumn("dbo.AspNetUserRoles", "RoleId");
            RenameColumn(table: "dbo.AspNetUserClaims", name: "ApplicationUser_Id", newName: "UserId");
            RenameColumn(table: "dbo.AspNetUserLogins", name: "ApplicationUser_Id", newName: "UserId");
            RenameColumn(table: "dbo.AspNetUserRoles", name: "ApplicationUser_Id", newName: "UserId");
            RenameColumn(table: "dbo.AspNetUserRoles", name: "IdentityRole_Id", newName: "RoleId");
            DropPrimaryKey("dbo.AspNetUserLogins");
            DropPrimaryKey("dbo.AspNetUserRoles");
            AddColumn("dbo.AspNetUsers", "Discriminator", c => c.String(nullable: false, maxLength: 128));
            AlterColumn("dbo.AspNetUsers", "Newsletter", c => c.Boolean());
            AlterColumn("dbo.AspNetUsers", "RewardPoints", c => c.Int());
            AlterColumn("dbo.AspNetUsers", "BasketId", c => c.Int());
            AlterColumn("dbo.AspNetUsers", "BuylistBasketId", c => c.Int());
            AlterColumn("dbo.AspNetUsers", "StoreCredit", c => c.Double());
            AlterColumn("dbo.AspNetUsers", "Email", c => c.String(maxLength: 256));
            AlterColumn("dbo.AspNetUsers", "UserName", c => c.String(nullable: false, maxLength: 256));
            AlterColumn("dbo.AspNetUserClaims", "UserId", c => c.String(nullable: false, maxLength: 128));
            AlterColumn("dbo.AspNetUserClaims", "UserId", c => c.String(nullable: false, maxLength: 128));
            AlterColumn("dbo.AspNetUserLogins", "LoginProvider", c => c.String(nullable: false, maxLength: 128));
            AlterColumn("dbo.AspNetUserLogins", "ProviderKey", c => c.String(nullable: false, maxLength: 128));
            AlterColumn("dbo.AspNetUserLogins", "UserId", c => c.String(nullable: false, maxLength: 128));
            AlterColumn("dbo.AspNetUserRoles", "UserId", c => c.String(nullable: false, maxLength: 128));
            AlterColumn("dbo.AspNetUserRoles", "RoleId", c => c.String(nullable: false, maxLength: 128));
            AlterColumn("dbo.AspNetRoles", "Name", c => c.String(nullable: false, maxLength: 256));
            AddPrimaryKey("dbo.AspNetUserLogins", new[] { "LoginProvider", "ProviderKey", "UserId" });
            AddPrimaryKey("dbo.AspNetUserRoles", new[] { "UserId", "RoleId" });
            CreateIndex("dbo.AspNetUsers", "UserName", unique: true, name: "UserNameIndex");
            CreateIndex("dbo.AspNetUserClaims", "UserId");
            CreateIndex("dbo.AspNetUserLogins", "UserId");
            CreateIndex("dbo.AspNetUserRoles", "UserId");
            CreateIndex("dbo.AspNetUserRoles", "RoleId");
            CreateIndex("dbo.AspNetRoles", "Name", unique: true, name: "RoleNameIndex");
        }

        public override void Down()
        {
            DropIndex("dbo.AspNetRoles", "RoleNameIndex");
            DropIndex("dbo.AspNetUserRoles", new[] { "RoleId" });
            DropIndex("dbo.AspNetUserRoles", new[] { "UserId" });
            DropIndex("dbo.AspNetUserLogins", new[] { "UserId" });
            DropIndex("dbo.AspNetUserClaims", new[] { "UserId" });
            DropIndex("dbo.AspNetUsers", "UserNameIndex");
            DropPrimaryKey("dbo.AspNetUserRoles");
            DropPrimaryKey("dbo.AspNetUserLogins");
            AlterColumn("dbo.AspNetRoles", "Name", c => c.String());
            AlterColumn("dbo.AspNetUserRoles", "RoleId", c => c.String(maxLength: 128));
            AlterColumn("dbo.AspNetUserRoles", "UserId", c => c.String(maxLength: 128));
            AlterColumn("dbo.AspNetUserLogins", "UserId", c => c.String(maxLength: 128));
            AlterColumn("dbo.AspNetUserLogins", "ProviderKey", c => c.String());
            AlterColumn("dbo.AspNetUserLogins", "LoginProvider", c => c.String());
            AlterColumn("dbo.AspNetUserClaims", "UserId", c => c.String(maxLength: 128));
            AlterColumn("dbo.AspNetUserClaims", "UserId", c => c.String());
            AlterColumn("dbo.AspNetUsers", "UserName", c => c.String());
            AlterColumn("dbo.AspNetUsers", "Email", c => c.String());
            AlterColumn("dbo.AspNetUsers", "StoreCredit", c => c.Double(nullable: false));
            AlterColumn("dbo.AspNetUsers", "BuylistBasketId", c => c.Int(nullable: false));
            AlterColumn("dbo.AspNetUsers", "BasketId", c => c.Int(nullable: false));
            AlterColumn("dbo.AspNetUsers", "RewardPoints", c => c.Int(nullable: false));
            AlterColumn("dbo.AspNetUsers", "Newsletter", c => c.Boolean(nullable: false));
            DropColumn("dbo.AspNetUsers", "Discriminator");
            AddPrimaryKey("dbo.AspNetUserRoles", new[] { "RoleId", "UserId" });
            AddPrimaryKey("dbo.AspNetUserLogins", "UserId");
            RenameColumn(table: "dbo.AspNetUserRoles", name: "RoleId", newName: "IdentityRole_Id");
            RenameColumn(table: "dbo.AspNetUserRoles", name: "UserId", newName: "ApplicationUser_Id");
            RenameColumn(table: "dbo.AspNetUserLogins", name: "UserId", newName: "ApplicationUser_Id");
            RenameColumn(table: "dbo.AspNetUserClaims", name: "UserId", newName: "ApplicationUser_Id");
            AddColumn("dbo.AspNetUserRoles", "RoleId", c => c.String(nullable: false, maxLength: 128));
            AddColumn("dbo.AspNetUserRoles", "UserId", c => c.String(nullable: false, maxLength: 128));
            AddColumn("dbo.AspNetUserLogins", "UserId", c => c.String(nullable: false, maxLength: 128));
            AddColumn("dbo.AspNetUserClaims", "UserId", c => c.String());
            CreateIndex("dbo.AspNetUserRoles", "IdentityRole_Id");
            CreateIndex("dbo.AspNetUserRoles", "ApplicationUser_Id");
            CreateIndex("dbo.AspNetUserLogins", "ApplicationUser_Id");
            CreateIndex("dbo.AspNetUserClaims", "ApplicationUser_Id");
            RenameTable(name: "dbo.AspNetRoles", newName: "IdentityRoles");
            RenameTable(name: "dbo.AspNetUserRoles", newName: "IdentityUserRoles");
            RenameTable(name: "dbo.AspNetUserLogins", newName: "IdentityUserLogins");
            RenameTable(name: "dbo.AspNetUserClaims", newName: "IdentityUserClaims");
            RenameTable(name: "dbo.AspNetUsers", newName: "ApplicationUsers");
        }
    }
}

The error when running update-database:

The object 'PK_dbo.AspNetUserLogins' is dependent on column 'UserId'.
ALTER TABLE DROP COLUMN UserId failed because one or more objects access this column.
Community
  • 1
  • 1
HarborneD
  • 23
  • 6

1 Answers1

0

I know you are not expecting such an answer, but my strong recommendation is not to merge. Let IdentityDbContext live its live, and it will let live you too. Its a (only) con. that you will need 2 separate db which is extra cost say in Azure I know, but still...

  1. If you try to live in a merged context with IdentityDbContext it will cost many hours to discover its behaviour, and its EF usage. Spare this time for yourself.
  2. More: Your API to Identities (Users, Roles, Login, Lockout, etc) are explicit classes and their methods, not EF. Strictly speaking you should not even know about the persistence (EF + RDBMS) of the Identity subsystem. (consider it a black box)
  3. You are right about relationships, but again: What would be your solution if you have a black box identity subsystem, which provide all services (including user/pwd/profile persistance) and you would like to build a relational DB for a business case which uses the exact same users? Just use the user id provided the by other subsystem in the DB. Do not worry about the referential integrity between the two system. Consider the following: in an authenticated session, your userid will be always valid, otherwise you have serious problem in the authentication process, so there will be most important thing to worry about...
g.pickardou
  • 32,346
  • 36
  • 123
  • 268
  • Another Problem i have is that i want to seed both databases and i am not sure how well this works with two contexts. – HarborneD Jun 25 '15 at 12:57
  • Also , for example , the address class has property public ApplicationUser Owner { get; set; } how do i populate that correctly if they are not part of the same context – HarborneD Jun 25 '15 at 12:59
  • Populate separately. The two context will nothing have to do each other, they will work. – g.pickardou Jun 25 '15 at 13:01
  • so i will be able to go address.Owner and it will give me the user? – HarborneD Jun 25 '15 at 13:05
  • Yeah looks like i was being an idiot and my context can handle the seeding and relationships i wanted... – HarborneD Jun 25 '15 at 13:08
  • Actually, you can keep the two DbContexts separate and still use the same database to save money. – ZX9 Nov 01 '19 at 15:11