我尝试在ASP.NET 6.1中将用户实体(ApplicationUser)中的多对多关系设置为自定义实体(组)。我使用带有ASP.Net Identity的股票标准MVC示例应用程序使用Code First和Migrations。运行Update-Database似乎工作得很好,因为我最终得到了所有的AspNet *表以及我的实体和链接表:
组
的 GroupAspNetUsers
我的ApplicationUser声明有一个Group集合,同样我的Group有一个ApplicationUser集合:
public class ApplicationUser : IdentityUser
{
public virtual ICollection<Group> Groups { get; set; }
我可以创建用户和群组,但就我而言,我无法解决如何链接它们的问题。我本以期望这样的事情发挥作用:
Group group = Context.Groups.Single(g => g.Id == 1);
var user = new ApplicationUser() { UserName = model.Email, Email = model.Email };
IdentityResult result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
// link this user to a group
group.ApplicationUsers.Add(user);
Context.SaveChanges();
然而,当我运行上面的代码时,我得到一个DbEntityValidationException,说明已经采用了用户名。
我已经尝试加载2个自定义实体并以这种方式链接它们,这会将记录插入到链接表中没问题。
因此,我不了解ApplicationUser的不同之处。
我的自定义实体和ASP.Net Identity实体应该使用与我的所有控制器从基本控制器继承的相同的DB上下文。
更新
我也试过从另一个方面接近这个(向用户添加一个组),没有任何运气:
IdentityResult result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
// attempting to add group to a user
user.Groups.Add(group);
Context.SaveChanges();
此代码运行时不会抛出错误,但它不会将记录添加到我的GroupAspNetUsers表中。
我的下一步是尝试创建一个单独的实体(例如UserInfo),该实体与ApplicationUser具有1对1的映射。然后我应该能够从UserInfo到Group设置多对多。
解
双插入问题源于UserManager.CreateAsync调用,该调用将在不同的线程上创建用户。当前线程不知道这一点,然后尝试再次插入用户。
将方法更改为UserMannager.Create解决了这个问题,但是@Horizon_Net指出混合身份和上下文方法存在其他问题(我遇到过)。
解决方案是创建用户,然后重定向到另一个控制器以将用户链接到一个组。这没有任何障碍。
答案 0 :(得分:2)
问题不是来自您的群组。以下两行是问题
IdentityResult result = await UserManager.CreateAsync(user, model.Password);
...
Context.SaveChanges();
幕后发生的事情是,第一次调用会创建用户。通过第二次调用,它再次尝试插入此用户。这就是您收到此错误消息的原因。
通常,您应该避免混合使用Identity提供的方法并处理上下文本身。这可能会产生很多副作用(例如你的例子)。
供参考,请查看this thread