从基础asp.net标识用户创建继承用户

时间:2014-11-21 10:20:36

标签: c# asp.net entity-framework asp.net-mvc-4 asp.net-identity

我遇到的问题是我想在示例中创建N,两个用户对象(例如Customer& Supplier),这些对象都是asp.net IdentityUser对象所固有的。除了来自IdentityUser的数据之外,这些对象具有非常不同的附加数据。我想使用IdentityUser用户,因为这样可以灵活地处理身份验证和授权。

此示例已被删除,但应提供有关无法创建具体用户的充分信息(例如,供应商的客户)。我似乎需要使用UserManager对象,因为它还负责创建密码哈希和其他安全信息。

我收到以下错误:

{"附加类型'供应商'失败,因为同一类型的另一个实体已具有相同的主键值。使用'附加'方法或将实体的状态设置为“未更改”#39;或者'修改'如果图中的任何实体具有冲突的键值。这可能是因为某些实体是新的并且尚未收到数据库生成的键值。在这种情况下,请使用'添加'方法或“添加”#39;实体状态跟踪图形,然后将非新实体的状态设置为“未更改”。或者'修改'酌情。"}

IdentityUser固有的类

 public class Customer : IdentityUser
 {
    public string CustomerProperty { get; set; }
 }

 public class Supplier : IdentityUser
 {
    public string SupplierProperty { get; set; }
 }

数据库上下文类

 public class ApplicationDbContext : IdentityDbContext {

      public ApplicationDbContext() : base("ApplicationDbContext")
      {
         Database.SetInitializer(new ApplicationDbInitializer());
      }

      public DbSet<Customer> CustomerCollection { get; set; }
      public DbSet<Supplier> SupplierCollection { get; set; }
 }

引发异常的种子类

 public class ApplicationDbInitializer : DropCreateDatabaseAlways<ApplicationDbContext>
 {
    protected override void Seed(ApplicationDbContext context)
    {
        var userStore = new UserStore(context);
        var userManager = new UserManager(userStore);


        // Seed customer user which inherents from asp.net IdentityUser 
        var user = userManager.FindByEmail("customer@customer.com");
        if (user == null)
        {
            user = new User()
            {
                UserName = "customer@customer.com",
                Email = "customer@customer.com"
            };

            userManager.Create(user, userPassword);

            var customerUser = new Customer()
            {
                Id = user.Id,
                CustomerProperty = "Additional Info"
            };

            context.Entry(customerUser).State = EntityState.Modified;
            context.SaveChanges();
        }

        // Seed supplier user which inherents from asp.net IdentityUser 
        var user = userManager.FindByEmail("supplier@supplier.com");
        if (user == null)
        {
            user = new User()
            {
                UserName = "supplier@supplier.com",
                Email = "supplier@supplier.com"
            };

            userManager.Create(user, userPassword);

            var supplierUser = new Supplier()
            {
                Id = user.Id,
                IBAN = "212323424342234",
                Relationship = "OK"
            };

            context.Entry(supplierUser).State = EntityState.Modified;
            context.SaveChanges();
        }
    }
}

****更新****

下面的解决方案有效,但我仍然在努力解决两个问题:

  1. 我总是希望有一个与IdentityUser相关联的用户类型(例如,供应商的客户)。我虽然使用界面,但这不起作用。
  2. 如果我还在用户类型上向IdentityUser添加虚拟引用,我会得到一个“无法确定类型之间关联的主要结束”的应用程序&#39; ApplicaitonUser&#39;和#&#39;供应商&#39;。必须使用关系流畅API或数据注释显式配置此关联的主要结尾。&#39;异常。
  3.  public class Customer 
     {
        [Key]
        public int CustomerId { get;set; }
        public string CustomerProperty { get; set; }
    
        *public virtual User User { get; set; }*
    
     }
    
     public class Supplier 
     {
        [Key]
        public int SupplierId { get;set; }
        public string SupplierProperty { get; set; }
    
        *public virtual User User { get; set; }*
     }
    

    ** Class IdentityUser(有效)**

    public class User : IdentityUser
    {
        public virtual Supplier Supplier { get; set; }
        public virtual Customer Customer { get; set; }
    }
    

    ** Class IdentityUser(我想要的)**

    public class User : IdentityUser
    {
        public virtual IConcreteUser ConcreteUser{ get; set; }
    }
    

    数据库上下文类

     public class ApplicationDbContext : IdentityDbContext {
    
          public ApplicationDbContext() : base("ApplicationDbContext")
          {
             Database.SetInitializer(new ApplicationDbInitializer());
          }
    
          public DbSet<Customer> CustomerCollection { get; set; }
          public DbSet<Supplier> SupplierCollection { get; set; }
     }
    

    **播种班**

     public class ApplicationDbInitializer : DropCreateDatabaseAlways<ApplicationDbContext>
     {
    protected override void Seed(ApplicationDbContext context)
    {
        var userStore = new UserStore(context);
        var userManager = new UserManager(userStore);
        var roleManager = new RoleManager(roleStore);
    
        var user = userManager.FindByEmail("customer@customer.com");
        if (user == null)
        {
            user = new ApplicationUser()
            {
                UserName = "customer@customer.com",
                Email = "customer@customer.com"
                Customer = new Customer()
                {
                    CustomerProperty = "Additional Info"
                }
            };
    
            userManager.Create(user, userPassword);
            roleManager.AddUserToRole("Customer");
        }
    
        user = userManager.FindByEmail("supplier@supplier.com");
        if (user == null)
        {
            user = new ApplicationUser()
            {
                UserName = "supplier@supplier.com",
                Email = "supplier@supplier.com",
                Supplier = new Supplier()
                {
                    IBAN = "212323424342234",
                    Relationship = "OK"
                }
            };
    
            userManager.Create(user, userPassword);
            roleManager.AddUserToRole("Supplier");
        }
    }
    

    }

2 个答案:

答案 0 :(得分:8)

正如其他人一样,我认为这是一个设计问题。有一些替代方法,如:

  1. 使用角色来定义“用户类型”(用户可以是供应商和客户)
  2. 使SupplierCustomer实体成为关系而不是用户的扩展
  3. e.g:

    public class ApplicationUser : IdentityUser
    {
        public virtual Customer Customer { get; set; }
        public virtual Supplier Supplier { get; set; }
    }
    
    public class Customer
    {
        [Key]
        public int Id { get; set; }
    
        public virtual ApplicationUser User { get; set; }
        public string CustomerProperty { get; set; }
    }
    
    public class Supplier
    {
        [Key]
        public int Id { get; set; }
    
        public virtual ApplicationUser User { get; set; }
        public string SupplierProperty { get; set; }
    }
    
    public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
    {
        public DbSet<Customer> Customers { get; set; }
        public DbSet<Supplier> Suppliers { get; set; }
    }
    
    public class ApplicationDbInitializer
                 : DropCreateDatabaseAlways<ApplicationDbContext>
    {
        protected override void Seed(ApplicationDbContext context)
        {
            var userStore = new UserStore(context);
            var userManager = new UserManager(userStore);
            var roleManager = new RoleManager(roleStore);
    
            var user = userManager.FindByEmail("customer@customer.com");
            if (user == null)
            {
                user = new ApplicationUser()
                {
                    UserName = "customer@customer.com",
                    Email = "customer@customer.com"
                    Customer = new Customer()
                    {
                        CustomerProperty = "Additional Info"
                    }
                };
    
                userManager.Create(user, userPassword);
                roleManager.AddUserToRole("Customer");
            }
    
            user = userManager.FindByEmail("supplier@supplier.com");
            if (user == null)
            {
                user = new ApplicationUser()
                {
                    UserName = "supplier@supplier.com",
                    Email = "supplier@supplier.com",
                    Supplier = new Supplier()
                    {
                        IBAN = "212323424342234",
                        Relationship = "OK"
                    }
                };
    
                userManager.Create(user, userPassword);
                roleManager.AddUserToRole("Supplier");
            }
        }
    }
    

    在您的逻辑中,您可以执行以下操作:

    if (User.IsInRole("Customer"))
    {
        // do something
    }
    

    免责声明:这不是“复制和粘贴”示例,只是让您了解不同的方法。

答案 1 :(得分:3)

我刚刚解决了类似的问题。我在AppUser中创建了抽象类型DomainUser的导航属性(继承自Identity User)

public class AppUser : IdentityUser
{
    public DomainUser DomainUser { get; set; }
}

DomainUser如下所示:

public abstract class DomainUser : IAggregateRoot
{
    public Guid Id { get; set; }
    public AppUser IdentityUser { get; set; }
}

我在所有具体域用户类型中继承DomainUser:

public class AdministrationUser : DomainUser
{
    public string SomeAdministrationProperty { get; set; }
}

public class SupplierUser : DomainUser
{
    public string SomeSupplierProperty { get; set; }
}

public class Customer : DomainUser
{
    public string SomeCustomerProperty { get; set; }
}

在OnModelCreating方法的DbContext中,我将Entity Framework配置为将从DomainUser继承的所有实体存储在单独的表中(称为Table per Concrete Type)。并在IdentityUser和DomainUser之间配置一对一关系:

modelBuilder.Entity<DomainUser>()
            .Map<AdministrationUser>(m =>
            {
                m.MapInheritedProperties();
                m.ToTable("AdministrationUsers");
            })
            .Map<SupplierUser>(m =>
            {
                m.MapInheritedProperties();
                m.ToTable("SupplierUsers");
            })
            .Map<Customer>(m =>
            {
                m.MapInheritedProperties();
                m.ToTable("Customers");
            });

modelBuilder.Entity<DomainUser>()
            .HasRequired(domainUser => domainUser.IdentityUser)
            .WithRequiredPrincipal(groomUser => groomUser.DomainUser);

此代码将“DomainUser_Id”列添加到表AspNetUsers,现在我可以访问AppUser中每个域用户和DomainUser导航属性中的IdentityUser导航属性。