我的用户实体:
public class User : IdentityUser<long>
{
public Office Office { get; set; } // not nullable
// ...other custom properties
}
假设我想创建一个新用户:
var user = new User {
UserName = "foo",
Email = "[email protected]",
EmailConfirmed = true,
Office = await context.Offices.SingleAsync(x => x.Name == "Head Office"),
};
await _userManager.CreateAsync(user, "password");
抛出:
重复的键值违反了唯一约束“PK_Office”
原因是
Office
在一个上下文中加载并在UserManager
封装的上下文中使用(它试图创建一个具有相同PK的新上下文)。
底层上下文未公开,因此无法执行
userManager.Context.Attach(office)
或类似操作。
我可以看到两种解决方法:
User.Office
为可空,然后:
var user = ...
await _userManager.CreateAsync(user, "password");
user.Office = ...
_context.Attach(user);
await _context.SaveChangesAsync();
但我不想这样做:我不想破坏我的域模型(没有办公室,用户就无法存在),因为UserManager
DbContext
而不是 UserManager
创建用户。但我也不想这样做,因为它为我处理所有与身份验证相关的事情,而且我不想承担任何责任。还有哪些其他选择?
(如果相关:这不是在网络请求的上下文中,而是实际上在控制台应用程序中。)
经过大量调查,我发现:如果
DbContext
和 UserManager
是从同一个容器解析的,那么后者的底层上下文将与前者是相同的实例。
这对我来说不起作用,因为在我的控制台应用程序中,这两件事是通过两个容器解决的。
最好的选择是确保它们从同一个容器中解析(即
ServiceProvider
)。
如果这不可能,那么还有其他选择:
Office
实体的 PK,然后 user.OfficeId = officeId
。