【发布时间】:2015-01-19 11:03:15
【问题描述】:
我有一个问题,我想创建 N,示例中的两个用户对象(例如客户和供应商)都是 asp.net IdentityUser 对象固有的。除了来自 IdentityUser 的数据之外,这些对象还有非常不同的附加数据。我想使用 IdentityUser 用户,因为这为我提供了一种灵活的方式来处理身份验证和授权。
这个例子已经非常精简,但应该提供足够的信息来说明无法创建一个具体的用户(例如供应商的客户)。看来我需要使用 UserManager 对象,因为它还负责创建例如密码哈希和其他安全信息。
我收到以下错误:
{“附加‘供应商’类型的实体失败,因为同一类型的另一个实体已经具有相同的主键值。当使用‘附加’方法或将实体的状态设置为如果图中的任何实体具有冲突的键值,则为“未更改”或“已修改”。这可能是因为某些实体是新的并且尚未接收到数据库生成的键值。在这种情况下,请使用“添加”方法或“添加” ' 实体状态来跟踪图表,然后根据需要将非新实体的状态设置为 'Unchanged' 或 'Modified'。"}
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();
}
}
}
**** 更新 ****
以下解决方案有效,但我仍在努力解决两个问题:
- 我总是希望将一种用户类型(例如供应商的客户)与 IdentityUser 相关联。我想使用一个界面,但这不起作用。
- 如果我还在用户类型上添加了对 IdentityUser 的虚拟引用,我会得到一个“无法确定“ApplicaitonUser”和“供应商”类型之间关联的主体端。必须使用关系流式 API 或数据注释显式配置此关联的主体端。例外。
类
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");
}
}
}
【问题讨论】:
-
我强烈建议修复损坏的设计。在 ASP.NET 级别上使用继承的需求为零。登录用户与您使用的任何数据库管理或功能组中的基础实体根本不同。 IE。做一个简单的 asp.net 用户,不要将 ot 绑定到您的复杂模型。将它们分开。
-
您是否尝试按照错误中的说明设置 EntityState.Addedd 而不是 EntityState.Modified?
-
我认为问题在于“混合状态”:它既不是
EntityState.Modified也不是EntityState.Added,因为已经添加了User,但是例如Supplier不是... -
@TomTom:如果我保留用户(例如客户和供应商),我怎么知道哪个用户登录?他们都将使用来自 IdentityUser 的凭据登录。
-
这又是 IMO 糟糕的设计。要求供应商提供 TFA 很好,但那也很可能成为客户,不是吗?因此,如果用户是供应商,只需启用/执行 TFA。无论如何,其他安全规则应该是基于角色的 IMO...
标签: c# asp.net entity-framework asp.net-mvc-4 asp.net-identity