Sql server 让IdentityManager在两个不同的数据库上进行更改

Sql server 让IdentityManager在两个不同的数据库上进行更改,sql-server,entity-framework,asp.net-identity,asp.net-identity-2,identityserver3,Sql Server,Entity Framework,Asp.net Identity,Asp.net Identity 2,Identityserver3,我们有两个数据库,其中包含用户表,如下所示: MasterDB.AspNetUsers Customer1DB.AspNetUsers 我们使用MasterDb登录用户,然后将他们连接到客户数据库,例如Customer1DB(或其他客户数据库,具体取决于用户)。基于ASP.NET Identity Framework,两个用户表具有相同的模式,我们可以使用它们来管理MasterDb上的用户 现在我想要的是对MasterDb用户记录执行的任何更改,将其镜像到客户数据库(具有相同的用户Id)上的

我们有两个数据库,其中包含用户表,如下所示:

  • MasterDB.AspNetUsers
  • Customer1DB.AspNetUsers
我们使用MasterDb登录用户,然后将他们连接到客户数据库,例如Customer1DB(或其他客户数据库,具体取决于用户)。基于ASP.NET Identity Framework,两个用户表具有相同的模式,我们可以使用它们来管理MasterDb上的用户

现在我想要的是对MasterDb用户记录执行的任何更改,将其镜像到客户数据库(具有相同的用户Id)上的用户表。我想知道做这件事最好的方法是什么?我是否需要修改
UserStore
RoleStore
UserManager
rolemager
上的所有操作?我有一个函数,可以获取用户ID,并将其从第一个db添加或更新到第二个db,但我不确定应该如何将其集成到Identity Framework实现中


谢谢

我想你有两个选择:

  • 为所需的存储和功能创建适配器。适配器将在两个数据库上调用相同的方法

  • 在Master DbContext中,保存更改时,查看ChangeTracker并将更改复制到另一个DbContext

  • 每种方法都有其优点和不便之处

    1. 适配器示例:

    class MultiDatabaseUserStore<T> : IUserStore<T>
        where T : IdentityUser
    {
        private readonly UserStore<T>[] stores;
    
        public MultiDatabaseUserStore(params IdentityDbContext[] dbContexts)
        {
            if (dbContexts == null || dbContexts.Length <= 0)
            {
                throw new ArgumentException("At least one db context is required.", "dbContexts");
            }
    
            this.stores = dbContexts.Select(x => new UserStore<T>(x)).ToArray();
        }
    
        public void Dispose()
        {
            foreach (var store in this.stores)
            {
                store.Dispose();
            }
        }
    
        public Task CreateAsync(T user)
        {
            return this.ExecuteOnAll(x => x.CreateAsync(user));
        }
    
        public Task UpdateAsync(T user)
        {
            return this.ExecuteOnAll(x => x.UpdateAsync(user));
        }
    
        public Task DeleteAsync(T user)
        {
            return this.ExecuteOnAll(x => x.DeleteAsync(user));
        }
    
        public Task<T> FindByIdAsync(string userId)
        {
            return this.stores.First().FindByIdAsync(userId);
        }
    
        public Task<T> FindByNameAsync(string userName)
        {
            return this.stores.First().FindByNameAsync(userName);
        }
    
        private Task ExecuteOnAll(Func<UserStore<T>, Task> function)
        {
            return Task.WhenAll(this.stores.Select(function));
        }
    }
    
    getChangeStoreReplicate()
    变成:

    private IEnumerable<Action<IdentityDbContext>> GetChangesToReplicate()
    {
        if (!this.IsReplicatingChanges) // Flag
        {
            // Return null when not activated
            return null;
        }
    
        var actions = new List<Action<IdentityDbContext>>();
        var changedEntries = this.ChangeTracker.Entries().Where(x => x.State != EntityState.Unchanged);
    
        foreach (var u in changedEntries)
        {
            var entity = u.Entity;
            var state = u.State;
    
            actions.Add(db =>
            {
                db.Set(entity.GetType()).Attach(entity);
                db.Entry(entity).State = state;
            });
        }
    
        return actions;
    }
    
    private IEnumerable GetChangeStoreReplicate()
    {
    如果(!this.isreplicationchanges)//标志
    {
    //未激活时返回null
    返回null;
    }
    var actions=新列表();
    var changedEntries=this.ChangeTracker.Entries()。其中(x=>x.State!=EntityState.Unchanged);
    foreach(换币厂的var u)
    {
    var实体=美国实体;
    var状态=美国状态;
    actions.Add(db=>
    {
    db.Set(entity.GetType()).Attach(entity);
    db.Entry(entity).State=状态;
    });
    }
    返回动作;
    }
    

    别忘了将空检查添加到
    SaveReplicatedChanges()

    …奖金将授予Chris的答案:)感谢您的详细回答,特别是包括代码。我想我会选择选项2。谢谢:)再考虑一下,我发现了一个改进的#2,它适用于所有场景。顺便说一句,对于获得更改的用户条目,您可以使用
    ChangeTracker.entries()
    而不是
    Where
    子句。是的,这比Where更好。。。但是我添加了改进的#2,它不再检查类型。
    class MasterDb : IdentityDbContext
    {
        public MasterDb()
        {
        }
    
        public override int SaveChanges()
        {
            var changes = this.GetChangesToReplicate();
    
            var i = base.SaveChanges();
    
            this.SaveReplicatedChanges(changes);
    
            return i;
        }
    
        public override Task<int> SaveChangesAsync()
        {
            return Task.Run(async () =>
            {
                var changes = this.GetChangesToReplicate();
    
                var i = await base.SaveChangesAsync();
    
                this.SaveReplicatedChanges(changes);
    
                return i;
            });
        }
    
        private void SaveReplicatedChanges(IEnumerable<Action<IdentityDbContext>> changes)
        {
            if (changes != null)
            {
                using (var db = new Customer1DB())
                {
                    foreach (var change in changes)
                    {
                        change(db);
                    }
    
                    db.SaveChanges();
                }
            }
        }
    
        private IEnumerable<Action<IdentityDbContext>> GetChangesToReplicate()
        {
            var actions = new List<Action<IdentityDbContext>>();
            var userTye = typeof(IdentityUser);
            var changedEntries = this.ChangeTracker.Entries();
            var users = changedEntries.Where(x => x.Entity.GetType() == userTye).ToList();
    
            foreach (var u in users)
            {
                switch (u.State)
                {
                    case EntityState.Added:
                        var userToAdd = (IdentityUser)u.Entity;
                        actions.Add(db => db.Users.Add(userToAdd));
                        break;
    
                    case EntityState.Modified:
                        var userToUpdate = (IdentityUser)u.Entity; ;
                        actions.Add(db =>
                        {
                            db.Users.Attach(userToUpdate);
                            db.Entry(userToUpdate).State = EntityState.Modified;
                        });
                        break;
    
                    case EntityState.Deleted:
                        var userToDelete = (IdentityUser)u.Entity; ;
                        actions.Add(db =>
                        {
                            db.Users.Attach(userToDelete);
                            db.Entry(userToDelete).State = EntityState.Deleted;
                        });
                        break;
                }
            }
    
            return actions;
        }
    }
    
    var dbContext = new MasterDb { IsReplicatingChanges = true };
    var userManager = new UserManager<IdentityUser>(new UserStore<IdentityUser>(dbContext));
    var roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(dbContext));
    
    private IEnumerable<Action<IdentityDbContext>> GetChangesToReplicate()
    {
        if (!this.IsReplicatingChanges) // Flag
        {
            // Return null when not activated
            return null;
        }
    
        var actions = new List<Action<IdentityDbContext>>();
        var changedEntries = this.ChangeTracker.Entries().Where(x => x.State != EntityState.Unchanged);
    
        foreach (var u in changedEntries)
        {
            var entity = u.Entity;
            var state = u.State;
    
            actions.Add(db =>
            {
                db.Set(entity.GetType()).Attach(entity);
                db.Entry(entity).State = state;
            });
        }
    
        return actions;
    }